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);
3181 Roo.bootstrap.NavGroup.register(this);
3185 * Fires when the active item changes
3186 * @param {Roo.bootstrap.NavGroup} this
3187 * @param {Roo.bootstrap.Navbar.Item} item The item selected
3188 * @param {Roo.bootstrap.Navbar.Item} item The previously selected item
3195 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3206 getAutoCreate : function()
3208 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3215 if (['tabs','pills'].indexOf(this.type)!==-1) {
3216 cfg.cls += ' nav-' + this.type
3218 if (this.type!=='nav') {
3219 Roo.log('nav type must be nav/tabs/pills')
3221 cfg.cls += ' navbar-nav'
3224 if (this.parent().sidebar) {
3227 cls: 'dashboard-menu sidebar-menu'
3233 if (this.form === true) {
3239 if (this.align === 'right') {
3240 cfg.cls += ' navbar-right';
3242 cfg.cls += ' navbar-left';
3246 if (this.align === 'right') {
3247 cfg.cls += ' navbar-right';
3251 cfg.cls += ' navbar-inverse';
3259 * sets the active Navigation item
3260 * @param {Roo.bootstrap.NavItem} the new current navitem
3262 setActiveItem : function(item)
3265 Roo.each(this.navItems, function(v){
3270 v.setActive(false, true);
3277 item.setActive(true, true);
3278 this.fireEvent('changed', this, item, prev);
3283 * gets the active Navigation item
3284 * @return {Roo.bootstrap.NavItem} the current navitem
3286 getActive : function()
3290 Roo.each(this.navItems, function(v){
3301 indexOfNav : function()
3305 Roo.each(this.navItems, function(v,i){
3316 * adds a Navigation item
3317 * @param {Roo.bootstrap.NavItem} the navitem to add
3319 addItem : function(cfg)
3321 var cn = new Roo.bootstrap.NavItem(cfg);
3323 cn.parentId = this.id;
3324 cn.onRender(this.el, null);
3328 * register a Navigation item
3329 * @param {Roo.bootstrap.NavItem} the navitem to add
3331 register : function(item)
3333 this.navItems.push( item);
3334 item.navId = this.navId;
3339 getNavItem: function(tabId)
3342 Roo.each(this.navItems, function(e) {
3343 if (e.tabId == tabId) {
3353 setActiveNext : function()
3355 var i = this.indexOfNav(this.getActive());
3356 if (i > this.navItems.length) {
3359 this.setActiveItem(this.navItems[i+1]);
3361 setActivePrev : function()
3363 var i = this.indexOfNav(this.getActive());
3367 this.setActiveItem(this.navItems[i-1]);
3369 clearWasActive : function(except) {
3370 Roo.each(this.navItems, function(e) {
3371 if (e.tabId != except.tabId && e.was_active) {
3372 e.was_active = false;
3379 getWasActive : function ()
3382 Roo.each(this.navItems, function(e) {
3397 Roo.apply(Roo.bootstrap.NavGroup, {
3401 * register a Navigation Group
3402 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3404 register : function(navgrp)
3406 this.groups[navgrp.navId] = navgrp;
3410 * fetch a Navigation Group based on the navigation ID
3411 * @param {string} the navgroup to add
3412 * @returns {Roo.bootstrap.NavGroup} the navgroup
3414 get: function(navId) {
3415 if (typeof(this.groups[navId]) == 'undefined') {
3417 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3419 return this.groups[navId] ;
3434 * @class Roo.bootstrap.NavItem
3435 * @extends Roo.bootstrap.Component
3436 * Bootstrap Navbar.NavItem class
3437 * @cfg {String} href link to
3438 * @cfg {String} html content of button
3439 * @cfg {String} badge text inside badge
3440 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3441 * @cfg {String} glyphicon name of glyphicon
3442 * @cfg {String} icon name of font awesome icon
3443 * @cfg {Boolean} active Is item active
3444 * @cfg {Boolean} disabled Is item disabled
3446 * @cfg {Boolean} preventDefault (true | false) default false
3447 * @cfg {String} tabId the tab that this item activates.
3448 * @cfg {String} tagtype (a|span) render as a href or span?
3451 * Create a new Navbar Item
3452 * @param {Object} config The config object
3454 Roo.bootstrap.NavItem = function(config){
3455 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3460 * The raw click event for the entire grid.
3461 * @param {Roo.EventObject} e
3466 * Fires when the active item active state changes
3467 * @param {Roo.bootstrap.NavItem} this
3468 * @param {boolean} state the new state
3476 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3484 preventDefault : false,
3491 getAutoCreate : function(){
3499 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3501 if (this.disabled) {
3502 cfg.cls += ' disabled';
3505 if (this.href || this.html || this.glyphicon || this.icon) {
3509 href : this.href || "#",
3510 html: this.html || ''
3515 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3518 if(this.glyphicon) {
3519 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3524 cfg.cn[0].html += " <span class='caret'></span>";
3528 if (this.badge !== '') {
3530 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3538 initEvents: function() {
3539 // Roo.log('init events?');
3540 // Roo.log(this.el.dom);
3541 if (typeof (this.menu) != 'undefined') {
3542 this.menu.parentType = this.xtype;
3543 this.menu.triggerEl = this.el;
3544 this.addxtype(Roo.apply({}, this.menu));
3548 this.el.select('a',true).on('click', this.onClick, this);
3549 // at this point parent should be available..
3550 this.parent().register(this);
3553 onClick : function(e)
3556 if(this.preventDefault){
3559 if (this.disabled) {
3563 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3564 if (tg && tg.transition) {
3565 Roo.log("waiting for the transitionend");
3569 Roo.log("fire event clicked");
3570 if(this.fireEvent('click', this, e) === false){
3574 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3575 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3576 this.parent().setActiveItem(this);
3581 isActive: function () {
3584 setActive : function(state, fire, is_was_active)
3586 if (this.active && !state & this.navId) {
3587 this.was_active = true;
3588 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3590 nv.clearWasActive(this);
3594 this.active = state;
3597 this.el.removeClass('active');
3598 } else if (!this.el.hasClass('active')) {
3599 this.el.addClass('active');
3602 this.fireEvent('changed', this, state);
3605 // show a panel if it's registered and related..
3607 if (!this.navId || !this.tabId || !state || is_was_active) {
3611 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3615 var pan = tg.getPanelByName(this.tabId);
3619 // if we can not flip to new panel - go back to old nav highlight..
3620 if (false == tg.showPanel(pan)) {
3621 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3623 var onav = nv.getWasActive();
3625 onav.setActive(true, false, true);
3634 // this should not be here...
3635 setDisabled : function(state)
3637 this.disabled = state;
3639 this.el.removeClass('disabled');
3640 } else if (!this.el.hasClass('disabled')) {
3641 this.el.addClass('disabled');
3654 * <span> icon </span>
3655 * <span> text </span>
3656 * <span>badge </span>
3660 * @class Roo.bootstrap.NavSidebarItem
3661 * @extends Roo.bootstrap.NavItem
3662 * Bootstrap Navbar.NavSidebarItem class
3664 * Create a new Navbar Button
3665 * @param {Object} config The config object
3667 Roo.bootstrap.NavSidebarItem = function(config){
3668 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3673 * The raw click event for the entire grid.
3674 * @param {Roo.EventObject} e
3679 * Fires when the active item active state changes
3680 * @param {Roo.bootstrap.NavSidebarItem} this
3681 * @param {boolean} state the new state
3689 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3692 getAutoCreate : function(){
3697 href : this.href || '#',
3709 html : this.html || ''
3714 cfg.cls += ' active';
3718 if (this.glyphicon || this.icon) {
3719 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3720 a.cn.push({ tag : 'i', cls : c }) ;
3725 if (this.badge !== '') {
3726 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3730 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3731 a.cls += 'dropdown-toggle treeview' ;
3755 * @class Roo.bootstrap.Row
3756 * @extends Roo.bootstrap.Component
3757 * Bootstrap Row class (contains columns...)
3761 * @param {Object} config The config object
3764 Roo.bootstrap.Row = function(config){
3765 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3768 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3770 getAutoCreate : function(){
3789 * @class Roo.bootstrap.Element
3790 * @extends Roo.bootstrap.Component
3791 * Bootstrap Element class
3792 * @cfg {String} html contents of the element
3793 * @cfg {String} tag tag of the element
3794 * @cfg {String} cls class of the element
3797 * Create a new Element
3798 * @param {Object} config The config object
3801 Roo.bootstrap.Element = function(config){
3802 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3805 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3812 getAutoCreate : function(){
3837 * @class Roo.bootstrap.Pagination
3838 * @extends Roo.bootstrap.Component
3839 * Bootstrap Pagination class
3840 * @cfg {String} size xs | sm | md | lg
3841 * @cfg {Boolean} inverse false | true
3844 * Create a new Pagination
3845 * @param {Object} config The config object
3848 Roo.bootstrap.Pagination = function(config){
3849 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3852 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3858 getAutoCreate : function(){
3864 cfg.cls += ' inverse';
3870 cfg.cls += " " + this.cls;
3888 * @class Roo.bootstrap.PaginationItem
3889 * @extends Roo.bootstrap.Component
3890 * Bootstrap PaginationItem class
3891 * @cfg {String} html text
3892 * @cfg {String} href the link
3893 * @cfg {Boolean} preventDefault (true | false) default true
3894 * @cfg {Boolean} active (true | false) default false
3898 * Create a new PaginationItem
3899 * @param {Object} config The config object
3903 Roo.bootstrap.PaginationItem = function(config){
3904 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3909 * The raw click event for the entire grid.
3910 * @param {Roo.EventObject} e
3916 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
3920 preventDefault: true,
3924 getAutoCreate : function(){
3930 href : this.href ? this.href : '#',
3931 html : this.html ? this.html : ''
3941 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
3947 initEvents: function() {
3949 this.el.on('click', this.onClick, this);
3952 onClick : function(e)
3954 Roo.log('PaginationItem on click ');
3955 if(this.preventDefault){
3959 this.fireEvent('click', this, e);
3975 * @class Roo.bootstrap.Slider
3976 * @extends Roo.bootstrap.Component
3977 * Bootstrap Slider class
3980 * Create a new Slider
3981 * @param {Object} config The config object
3984 Roo.bootstrap.Slider = function(config){
3985 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
3988 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
3990 getAutoCreate : function(){
3994 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
3998 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4010 * Ext JS Library 1.1.1
4011 * Copyright(c) 2006-2007, Ext JS, LLC.
4013 * Originally Released Under LGPL - original licence link has changed is not relivant.
4016 * <script type="text/javascript">
4021 * @class Roo.grid.ColumnModel
4022 * @extends Roo.util.Observable
4023 * This is the default implementation of a ColumnModel used by the Grid. It defines
4024 * the columns in the grid.
4027 var colModel = new Roo.grid.ColumnModel([
4028 {header: "Ticker", width: 60, sortable: true, locked: true},
4029 {header: "Company Name", width: 150, sortable: true},
4030 {header: "Market Cap.", width: 100, sortable: true},
4031 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4032 {header: "Employees", width: 100, sortable: true, resizable: false}
4037 * The config options listed for this class are options which may appear in each
4038 * individual column definition.
4039 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4041 * @param {Object} config An Array of column config objects. See this class's
4042 * config objects for details.
4044 Roo.grid.ColumnModel = function(config){
4046 * The config passed into the constructor
4048 this.config = config;
4051 // if no id, create one
4052 // if the column does not have a dataIndex mapping,
4053 // map it to the order it is in the config
4054 for(var i = 0, len = config.length; i < len; i++){
4056 if(typeof c.dataIndex == "undefined"){
4059 if(typeof c.renderer == "string"){
4060 c.renderer = Roo.util.Format[c.renderer];
4062 if(typeof c.id == "undefined"){
4065 if(c.editor && c.editor.xtype){
4066 c.editor = Roo.factory(c.editor, Roo.grid);
4068 if(c.editor && c.editor.isFormField){
4069 c.editor = new Roo.grid.GridEditor(c.editor);
4071 this.lookup[c.id] = c;
4075 * The width of columns which have no width specified (defaults to 100)
4078 this.defaultWidth = 100;
4081 * Default sortable of columns which have no sortable specified (defaults to false)
4084 this.defaultSortable = false;
4088 * @event widthchange
4089 * Fires when the width of a column changes.
4090 * @param {ColumnModel} this
4091 * @param {Number} columnIndex The column index
4092 * @param {Number} newWidth The new width
4094 "widthchange": true,
4096 * @event headerchange
4097 * Fires when the text of a header changes.
4098 * @param {ColumnModel} this
4099 * @param {Number} columnIndex The column index
4100 * @param {Number} newText The new header text
4102 "headerchange": true,
4104 * @event hiddenchange
4105 * Fires when a column is hidden or "unhidden".
4106 * @param {ColumnModel} this
4107 * @param {Number} columnIndex The column index
4108 * @param {Boolean} hidden true if hidden, false otherwise
4110 "hiddenchange": true,
4112 * @event columnmoved
4113 * Fires when a column is moved.
4114 * @param {ColumnModel} this
4115 * @param {Number} oldIndex
4116 * @param {Number} newIndex
4118 "columnmoved" : true,
4120 * @event columlockchange
4121 * Fires when a column's locked state is changed
4122 * @param {ColumnModel} this
4123 * @param {Number} colIndex
4124 * @param {Boolean} locked true if locked
4126 "columnlockchange" : true
4128 Roo.grid.ColumnModel.superclass.constructor.call(this);
4130 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4132 * @cfg {String} header The header text to display in the Grid view.
4135 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4136 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4137 * specified, the column's index is used as an index into the Record's data Array.
4140 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4141 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4144 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4145 * Defaults to the value of the {@link #defaultSortable} property.
4146 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4149 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4152 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4155 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4158 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4161 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4162 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4163 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4164 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4167 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4170 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4174 * Returns the id of the column at the specified index.
4175 * @param {Number} index The column index
4176 * @return {String} the id
4178 getColumnId : function(index){
4179 return this.config[index].id;
4183 * Returns the column for a specified id.
4184 * @param {String} id The column id
4185 * @return {Object} the column
4187 getColumnById : function(id){
4188 return this.lookup[id];
4193 * Returns the column for a specified dataIndex.
4194 * @param {String} dataIndex The column dataIndex
4195 * @return {Object|Boolean} the column or false if not found
4197 getColumnByDataIndex: function(dataIndex){
4198 var index = this.findColumnIndex(dataIndex);
4199 return index > -1 ? this.config[index] : false;
4203 * Returns the index for a specified column id.
4204 * @param {String} id The column id
4205 * @return {Number} the index, or -1 if not found
4207 getIndexById : function(id){
4208 for(var i = 0, len = this.config.length; i < len; i++){
4209 if(this.config[i].id == id){
4217 * Returns the index for a specified column dataIndex.
4218 * @param {String} dataIndex The column dataIndex
4219 * @return {Number} the index, or -1 if not found
4222 findColumnIndex : function(dataIndex){
4223 for(var i = 0, len = this.config.length; i < len; i++){
4224 if(this.config[i].dataIndex == dataIndex){
4232 moveColumn : function(oldIndex, newIndex){
4233 var c = this.config[oldIndex];
4234 this.config.splice(oldIndex, 1);
4235 this.config.splice(newIndex, 0, c);
4236 this.dataMap = null;
4237 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4240 isLocked : function(colIndex){
4241 return this.config[colIndex].locked === true;
4244 setLocked : function(colIndex, value, suppressEvent){
4245 if(this.isLocked(colIndex) == value){
4248 this.config[colIndex].locked = value;
4250 this.fireEvent("columnlockchange", this, colIndex, value);
4254 getTotalLockedWidth : function(){
4256 for(var i = 0; i < this.config.length; i++){
4257 if(this.isLocked(i) && !this.isHidden(i)){
4258 this.totalWidth += this.getColumnWidth(i);
4264 getLockedCount : function(){
4265 for(var i = 0, len = this.config.length; i < len; i++){
4266 if(!this.isLocked(i)){
4273 * Returns the number of columns.
4276 getColumnCount : function(visibleOnly){
4277 if(visibleOnly === true){
4279 for(var i = 0, len = this.config.length; i < len; i++){
4280 if(!this.isHidden(i)){
4286 return this.config.length;
4290 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4291 * @param {Function} fn
4292 * @param {Object} scope (optional)
4293 * @return {Array} result
4295 getColumnsBy : function(fn, scope){
4297 for(var i = 0, len = this.config.length; i < len; i++){
4298 var c = this.config[i];
4299 if(fn.call(scope||this, c, i) === true){
4307 * Returns true if the specified column is sortable.
4308 * @param {Number} col The column index
4311 isSortable : function(col){
4312 if(typeof this.config[col].sortable == "undefined"){
4313 return this.defaultSortable;
4315 return this.config[col].sortable;
4319 * Returns the rendering (formatting) function defined for the column.
4320 * @param {Number} col The column index.
4321 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4323 getRenderer : function(col){
4324 if(!this.config[col].renderer){
4325 return Roo.grid.ColumnModel.defaultRenderer;
4327 return this.config[col].renderer;
4331 * Sets the rendering (formatting) function for a column.
4332 * @param {Number} col The column index
4333 * @param {Function} fn The function to use to process the cell's raw data
4334 * to return HTML markup for the grid view. The render function is called with
4335 * the following parameters:<ul>
4336 * <li>Data value.</li>
4337 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4338 * <li>css A CSS style string to apply to the table cell.</li>
4339 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4340 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4341 * <li>Row index</li>
4342 * <li>Column index</li>
4343 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4345 setRenderer : function(col, fn){
4346 this.config[col].renderer = fn;
4350 * Returns the width for the specified column.
4351 * @param {Number} col The column index
4354 getColumnWidth : function(col){
4355 return this.config[col].width * 1 || this.defaultWidth;
4359 * Sets the width for a column.
4360 * @param {Number} col The column index
4361 * @param {Number} width The new width
4363 setColumnWidth : function(col, width, suppressEvent){
4364 this.config[col].width = width;
4365 this.totalWidth = null;
4367 this.fireEvent("widthchange", this, col, width);
4372 * Returns the total width of all columns.
4373 * @param {Boolean} includeHidden True to include hidden column widths
4376 getTotalWidth : function(includeHidden){
4377 if(!this.totalWidth){
4378 this.totalWidth = 0;
4379 for(var i = 0, len = this.config.length; i < len; i++){
4380 if(includeHidden || !this.isHidden(i)){
4381 this.totalWidth += this.getColumnWidth(i);
4385 return this.totalWidth;
4389 * Returns the header for the specified column.
4390 * @param {Number} col The column index
4393 getColumnHeader : function(col){
4394 return this.config[col].header;
4398 * Sets the header for a column.
4399 * @param {Number} col The column index
4400 * @param {String} header The new header
4402 setColumnHeader : function(col, header){
4403 this.config[col].header = header;
4404 this.fireEvent("headerchange", this, col, header);
4408 * Returns the tooltip for the specified column.
4409 * @param {Number} col The column index
4412 getColumnTooltip : function(col){
4413 return this.config[col].tooltip;
4416 * Sets the tooltip for a column.
4417 * @param {Number} col The column index
4418 * @param {String} tooltip The new tooltip
4420 setColumnTooltip : function(col, tooltip){
4421 this.config[col].tooltip = tooltip;
4425 * Returns the dataIndex for the specified column.
4426 * @param {Number} col The column index
4429 getDataIndex : function(col){
4430 return this.config[col].dataIndex;
4434 * Sets the dataIndex for a column.
4435 * @param {Number} col The column index
4436 * @param {Number} dataIndex The new dataIndex
4438 setDataIndex : function(col, dataIndex){
4439 this.config[col].dataIndex = dataIndex;
4445 * Returns true if the cell is editable.
4446 * @param {Number} colIndex The column index
4447 * @param {Number} rowIndex The row index
4450 isCellEditable : function(colIndex, rowIndex){
4451 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4455 * Returns the editor defined for the cell/column.
4456 * return false or null to disable editing.
4457 * @param {Number} colIndex The column index
4458 * @param {Number} rowIndex The row index
4461 getCellEditor : function(colIndex, rowIndex){
4462 return this.config[colIndex].editor;
4466 * Sets if a column is editable.
4467 * @param {Number} col The column index
4468 * @param {Boolean} editable True if the column is editable
4470 setEditable : function(col, editable){
4471 this.config[col].editable = editable;
4476 * Returns true if the column is hidden.
4477 * @param {Number} colIndex The column index
4480 isHidden : function(colIndex){
4481 return this.config[colIndex].hidden;
4486 * Returns true if the column width cannot be changed
4488 isFixed : function(colIndex){
4489 return this.config[colIndex].fixed;
4493 * Returns true if the column can be resized
4496 isResizable : function(colIndex){
4497 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4500 * Sets if a column is hidden.
4501 * @param {Number} colIndex The column index
4502 * @param {Boolean} hidden True if the column is hidden
4504 setHidden : function(colIndex, hidden){
4505 this.config[colIndex].hidden = hidden;
4506 this.totalWidth = null;
4507 this.fireEvent("hiddenchange", this, colIndex, hidden);
4511 * Sets the editor for a column.
4512 * @param {Number} col The column index
4513 * @param {Object} editor The editor object
4515 setEditor : function(col, editor){
4516 this.config[col].editor = editor;
4520 Roo.grid.ColumnModel.defaultRenderer = function(value){
4521 if(typeof value == "string" && value.length < 1){
4527 // Alias for backwards compatibility
4528 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4531 * Ext JS Library 1.1.1
4532 * Copyright(c) 2006-2007, Ext JS, LLC.
4534 * Originally Released Under LGPL - original licence link has changed is not relivant.
4537 * <script type="text/javascript">
4541 * @class Roo.LoadMask
4542 * A simple utility class for generically masking elements while loading data. If the element being masked has
4543 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4544 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4545 * element's UpdateManager load indicator and will be destroyed after the initial load.
4547 * Create a new LoadMask
4548 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4549 * @param {Object} config The config object
4551 Roo.LoadMask = function(el, config){
4552 this.el = Roo.get(el);
4553 Roo.apply(this, config);
4555 this.store.on('beforeload', this.onBeforeLoad, this);
4556 this.store.on('load', this.onLoad, this);
4557 this.store.on('loadexception', this.onLoadException, this);
4558 this.removeMask = false;
4560 var um = this.el.getUpdateManager();
4561 um.showLoadIndicator = false; // disable the default indicator
4562 um.on('beforeupdate', this.onBeforeLoad, this);
4563 um.on('update', this.onLoad, this);
4564 um.on('failure', this.onLoad, this);
4565 this.removeMask = true;
4569 Roo.LoadMask.prototype = {
4571 * @cfg {Boolean} removeMask
4572 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4573 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4577 * The text to display in a centered loading message box (defaults to 'Loading...')
4581 * @cfg {String} msgCls
4582 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4584 msgCls : 'x-mask-loading',
4587 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4593 * Disables the mask to prevent it from being displayed
4595 disable : function(){
4596 this.disabled = true;
4600 * Enables the mask so that it can be displayed
4602 enable : function(){
4603 this.disabled = false;
4606 onLoadException : function()
4610 if (typeof(arguments[3]) != 'undefined') {
4611 Roo.MessageBox.alert("Error loading",arguments[3]);
4615 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4616 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4625 this.el.unmask(this.removeMask);
4630 this.el.unmask(this.removeMask);
4634 onBeforeLoad : function(){
4636 this.el.mask(this.msg, this.msgCls);
4641 destroy : function(){
4643 this.store.un('beforeload', this.onBeforeLoad, this);
4644 this.store.un('load', this.onLoad, this);
4645 this.store.un('loadexception', this.onLoadException, this);
4647 var um = this.el.getUpdateManager();
4648 um.un('beforeupdate', this.onBeforeLoad, this);
4649 um.un('update', this.onLoad, this);
4650 um.un('failure', this.onLoad, this);
4661 * @class Roo.bootstrap.Table
4662 * @extends Roo.bootstrap.Component
4663 * Bootstrap Table class
4664 * @cfg {String} cls table class
4665 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4666 * @cfg {String} bgcolor Specifies the background color for a table
4667 * @cfg {Number} border Specifies whether the table cells should have borders or not
4668 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4669 * @cfg {Number} cellspacing Specifies the space between cells
4670 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4671 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4672 * @cfg {String} sortable Specifies that the table should be sortable
4673 * @cfg {String} summary Specifies a summary of the content of a table
4674 * @cfg {Number} width Specifies the width of a table
4675 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4677 * @cfg {boolean} striped Should the rows be alternative striped
4678 * @cfg {boolean} bordered Add borders to the table
4679 * @cfg {boolean} hover Add hover highlighting
4680 * @cfg {boolean} condensed Format condensed
4681 * @cfg {boolean} responsive Format condensed
4682 * @cfg {Boolean} loadMask (true|false) default false
4683 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4684 * @cfg {Boolean} thead (true|false) generate thead, default true
4685 * @cfg {Boolean} RowSelection (true|false) default false
4686 * @cfg {Boolean} CellSelection (true|false) default false
4688 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4692 * Create a new Table
4693 * @param {Object} config The config object
4696 Roo.bootstrap.Table = function(config){
4697 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4700 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4701 this.sm = this.selModel;
4702 this.sm.xmodule = this.xmodule || false;
4704 if (this.cm && typeof(this.cm.config) == 'undefined') {
4705 this.colModel = new Roo.grid.ColumnModel(this.cm);
4706 this.cm = this.colModel;
4707 this.cm.xmodule = this.xmodule || false;
4710 this.store= Roo.factory(this.store, Roo.data);
4711 this.ds = this.store;
4712 this.ds.xmodule = this.xmodule || false;
4715 if (this.footer && this.store) {
4716 this.footer.dataSource = this.ds;
4717 this.footer = Roo.factory(this.footer);
4724 * Fires when a cell is clicked
4725 * @param {Roo.bootstrap.Table} this
4726 * @param {Roo.Element} el
4727 * @param {Number} rowIndex
4728 * @param {Number} columnIndex
4729 * @param {Roo.EventObject} e
4733 * @event celldblclick
4734 * Fires when a cell is double clicked
4735 * @param {Roo.bootstrap.Table} this
4736 * @param {Roo.Element} el
4737 * @param {Number} rowIndex
4738 * @param {Number} columnIndex
4739 * @param {Roo.EventObject} e
4741 "celldblclick" : true,
4744 * Fires when a row is clicked
4745 * @param {Roo.bootstrap.Table} this
4746 * @param {Roo.Element} el
4747 * @param {Number} rowIndex
4748 * @param {Roo.EventObject} e
4752 * @event rowdblclick
4753 * Fires when a row is double clicked
4754 * @param {Roo.bootstrap.Table} this
4755 * @param {Roo.Element} el
4756 * @param {Number} rowIndex
4757 * @param {Roo.EventObject} e
4759 "rowdblclick" : true,
4762 * Fires when a mouseover occur
4763 * @param {Roo.bootstrap.Table} this
4764 * @param {Roo.Element} el
4765 * @param {Number} rowIndex
4766 * @param {Number} columnIndex
4767 * @param {Roo.EventObject} e
4772 * Fires when a mouseout occur
4773 * @param {Roo.bootstrap.Table} this
4774 * @param {Roo.Element} el
4775 * @param {Number} rowIndex
4776 * @param {Number} columnIndex
4777 * @param {Roo.EventObject} e
4782 * Fires when a row is rendered, so you can change add a style to it.
4783 * @param {Roo.bootstrap.Table} this
4784 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
4791 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4815 RowSelection : false,
4816 CellSelection : false,
4819 // Roo.Element - the tbody
4822 getAutoCreate : function(){
4823 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4832 cfg.cls += ' table-striped';
4836 cfg.cls += ' table-hover';
4838 if (this.bordered) {
4839 cfg.cls += ' table-bordered';
4841 if (this.condensed) {
4842 cfg.cls += ' table-condensed';
4844 if (this.responsive) {
4845 cfg.cls += ' table-responsive';
4849 cfg.cls+= ' ' +this.cls;
4852 // this lot should be simplifed...
4855 cfg.align=this.align;
4858 cfg.bgcolor=this.bgcolor;
4861 cfg.border=this.border;
4863 if (this.cellpadding) {
4864 cfg.cellpadding=this.cellpadding;
4866 if (this.cellspacing) {
4867 cfg.cellspacing=this.cellspacing;
4870 cfg.frame=this.frame;
4873 cfg.rules=this.rules;
4875 if (this.sortable) {
4876 cfg.sortable=this.sortable;
4879 cfg.summary=this.summary;
4882 cfg.width=this.width;
4885 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
4888 if(this.store || this.cm){
4890 cfg.cn.push(this.renderHeader());
4893 cfg.cn.push(this.renderBody());
4896 cfg.cn.push(this.renderFooter());
4899 cfg.cls+= ' TableGrid';
4902 return { cn : [ cfg ] };
4905 initEvents : function()
4907 if(!this.store || !this.cm){
4911 //Roo.log('initEvents with ds!!!!');
4913 this.mainBody = this.el.select('tbody', true).first();
4918 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4919 e.on('click', _this.sort, _this);
4922 this.el.on("click", this.onClick, this);
4923 this.el.on("dblclick", this.onDblClick, this);
4925 this.parent().el.setStyle('position', 'relative');
4927 this.footer.parentId = this.id;
4928 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
4931 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
4933 this.store.on('load', this.onLoad, this);
4934 this.store.on('beforeload', this.onBeforeLoad, this);
4935 this.store.on('update', this.onUpdate, this);
4939 onMouseover : function(e, el)
4941 var cell = Roo.get(el);
4947 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4948 cell = cell.findParent('td', false, true);
4951 var row = cell.findParent('tr', false, true);
4952 var cellIndex = cell.dom.cellIndex;
4953 var rowIndex = row.dom.rowIndex - 1; // start from 0
4955 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
4959 onMouseout : function(e, el)
4961 var cell = Roo.get(el);
4967 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4968 cell = cell.findParent('td', false, true);
4971 var row = cell.findParent('tr', false, true);
4972 var cellIndex = cell.dom.cellIndex;
4973 var rowIndex = row.dom.rowIndex - 1; // start from 0
4975 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
4979 onClick : function(e, el)
4981 var cell = Roo.get(el);
4983 if(!cell || (!this.CellSelection && !this.RowSelection)){
4988 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4989 cell = cell.findParent('td', false, true);
4992 var row = cell.findParent('tr', false, true);
4993 var cellIndex = cell.dom.cellIndex;
4994 var rowIndex = row.dom.rowIndex - 1;
4996 if(this.CellSelection){
4997 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5000 if(this.RowSelection){
5001 this.fireEvent('rowclick', this, row, rowIndex, e);
5007 onDblClick : function(e,el)
5009 var cell = Roo.get(el);
5011 if(!cell || (!this.CellSelection && !this.RowSelection)){
5015 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5016 cell = cell.findParent('td', false, true);
5019 var row = cell.findParent('tr', false, true);
5020 var cellIndex = cell.dom.cellIndex;
5021 var rowIndex = row.dom.rowIndex - 1;
5023 if(this.CellSelection){
5024 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5027 if(this.RowSelection){
5028 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5032 sort : function(e,el)
5034 var col = Roo.get(el)
5036 if(!col.hasClass('sortable')){
5040 var sort = col.attr('sort');
5043 if(col.hasClass('glyphicon-arrow-up')){
5047 this.store.sortInfo = {field : sort, direction : dir};
5050 Roo.log("calling footer first");
5051 this.footer.onClick('first');
5054 this.store.load({ params : { start : 0 } });
5058 renderHeader : function()
5067 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5069 var config = cm.config[i];
5074 html: cm.getColumnHeader(i)
5077 if(typeof(config.hidden) != 'undefined' && config.hidden){
5078 c.style += ' display:none;';
5081 if(typeof(config.dataIndex) != 'undefined'){
5082 c.sort = config.dataIndex;
5085 if(typeof(config.sortable) != 'undefined' && config.sortable){
5089 if(typeof(config.align) != 'undefined' && config.align.length){
5090 c.style += ' text-align:' + config.align + ';';
5093 if(typeof(config.width) != 'undefined'){
5094 c.style += ' width:' + config.width + 'px;';
5103 renderBody : function()
5113 colspan : this.cm.getColumnCount()
5123 renderFooter : function()
5133 colspan : this.cm.getColumnCount()
5147 Roo.log('ds onload');
5152 var ds = this.store;
5154 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5155 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5157 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5158 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5161 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5162 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5166 var tbody = this.mainBody;
5168 if(ds.getCount() > 0){
5169 ds.data.each(function(d,rowIndex){
5170 var row = this.renderRow(cm, ds, rowIndex);
5172 tbody.createChild(row);
5176 if(row.cellObjects.length){
5177 Roo.each(row.cellObjects, function(r){
5178 _this.renderCellObject(r);
5185 Roo.each(this.el.select('tbody td', true).elements, function(e){
5186 e.on('mouseover', _this.onMouseover, _this);
5189 Roo.each(this.el.select('tbody td', true).elements, function(e){
5190 e.on('mouseout', _this.onMouseout, _this);
5193 //if(this.loadMask){
5194 // this.maskEl.hide();
5199 onUpdate : function(ds,record)
5201 this.refreshRow(record);
5203 onRemove : function(ds, record, index, isUpdate){
5204 if(isUpdate !== true){
5205 this.fireEvent("beforerowremoved", this, index, record);
5207 var bt = this.mainBody.dom;
5209 bt.removeChild(bt.rows[index]);
5212 if(isUpdate !== true){
5213 //this.stripeRows(index);
5214 //this.syncRowHeights(index, index);
5216 this.fireEvent("rowremoved", this, index, record);
5221 refreshRow : function(record){
5222 var ds = this.store, index;
5223 if(typeof record == 'number'){
5225 record = ds.getAt(index);
5227 index = ds.indexOf(record);
5229 this.insertRow(ds, index, true);
5230 this.onRemove(ds, record, index+1, true);
5231 //this.syncRowHeights(index, index);
5233 this.fireEvent("rowupdated", this, index, record);
5236 insertRow : function(dm, rowIndex, isUpdate){
5239 this.fireEvent("beforerowsinserted", this, rowIndex);
5241 //var s = this.getScrollState();
5242 var row = this.renderRow(this.cm, this.store, rowIndex);
5243 // insert before rowIndex..
5244 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5248 if(row.cellObjects.length){
5249 Roo.each(row.cellObjects, function(r){
5250 _this.renderCellObject(r);
5255 this.fireEvent("rowsinserted", this, rowIndex);
5256 //this.syncRowHeights(firstRow, lastRow);
5257 //this.stripeRows(firstRow);
5264 getRowDom : function(rowIndex)
5266 // not sure if I need to check this.. but let's do it anyway..
5267 return (this.mainBody.dom.rows && (rowIndex-1) < this.mainBody.dom.rows.length ) ?
5268 this.mainBody.dom.rows[rowIndex] : false
5270 // returns the object tree for a tr..
5273 renderRow : function(cm, ds, rowIndex) {
5275 var d = ds.getAt(rowIndex);
5282 var cellObjects = [];
5284 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5285 var config = cm.config[i];
5287 var renderer = cm.getRenderer(i);
5291 if(typeof(renderer) !== 'undefined'){
5292 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5294 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5295 // and are rendered into the cells after the row is rendered - using the id for the element.
5297 if(typeof(value) === 'object'){
5307 rowIndex : rowIndex,
5312 this.fireEvent('rowclass', this, rowcfg);
5316 cls : rowcfg.rowClass,
5318 html: (typeof(value) === 'object') ? '' : value
5325 if(typeof(config.hidden) != 'undefined' && config.hidden){
5326 td.style += ' display:none;';
5329 if(typeof(config.align) != 'undefined' && config.align.length){
5330 td.style += ' text-align:' + config.align + ';';
5333 if(typeof(config.width) != 'undefined'){
5334 td.style += ' width:' + config.width + 'px;';
5341 row.cellObjects = cellObjects;
5349 onBeforeLoad : function()
5351 //Roo.log('ds onBeforeLoad');
5355 //if(this.loadMask){
5356 // this.maskEl.show();
5362 this.el.select('tbody', true).first().dom.innerHTML = '';
5365 getSelectionModel : function(){
5367 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5369 return this.selModel;
5372 * Render the Roo.bootstrap object from renderder
5374 renderCellObject : function(r)
5378 var t = r.cfg.render(r.container);
5381 Roo.each(r.cfg.cn, function(c){
5383 container: t.getChildContainer(),
5386 _this.renderCellObject(child);
5403 * @class Roo.bootstrap.TableCell
5404 * @extends Roo.bootstrap.Component
5405 * Bootstrap TableCell class
5406 * @cfg {String} html cell contain text
5407 * @cfg {String} cls cell class
5408 * @cfg {String} tag cell tag (td|th) default td
5409 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5410 * @cfg {String} align Aligns the content in a cell
5411 * @cfg {String} axis Categorizes cells
5412 * @cfg {String} bgcolor Specifies the background color of a cell
5413 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5414 * @cfg {Number} colspan Specifies the number of columns a cell should span
5415 * @cfg {String} headers Specifies one or more header cells a cell is related to
5416 * @cfg {Number} height Sets the height of a cell
5417 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5418 * @cfg {Number} rowspan Sets the number of rows a cell should span
5419 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5420 * @cfg {String} valign Vertical aligns the content in a cell
5421 * @cfg {Number} width Specifies the width of a cell
5424 * Create a new TableCell
5425 * @param {Object} config The config object
5428 Roo.bootstrap.TableCell = function(config){
5429 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5432 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5452 getAutoCreate : function(){
5453 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5473 cfg.align=this.align
5479 cfg.bgcolor=this.bgcolor
5482 cfg.charoff=this.charoff
5485 cfg.colspan=this.colspan
5488 cfg.headers=this.headers
5491 cfg.height=this.height
5494 cfg.nowrap=this.nowrap
5497 cfg.rowspan=this.rowspan
5500 cfg.scope=this.scope
5503 cfg.valign=this.valign
5506 cfg.width=this.width
5525 * @class Roo.bootstrap.TableRow
5526 * @extends Roo.bootstrap.Component
5527 * Bootstrap TableRow class
5528 * @cfg {String} cls row class
5529 * @cfg {String} align Aligns the content in a table row
5530 * @cfg {String} bgcolor Specifies a background color for a table row
5531 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5532 * @cfg {String} valign Vertical aligns the content in a table row
5535 * Create a new TableRow
5536 * @param {Object} config The config object
5539 Roo.bootstrap.TableRow = function(config){
5540 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5543 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5551 getAutoCreate : function(){
5552 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5562 cfg.align = this.align;
5565 cfg.bgcolor = this.bgcolor;
5568 cfg.charoff = this.charoff;
5571 cfg.valign = this.valign;
5589 * @class Roo.bootstrap.TableBody
5590 * @extends Roo.bootstrap.Component
5591 * Bootstrap TableBody class
5592 * @cfg {String} cls element class
5593 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5594 * @cfg {String} align Aligns the content inside the element
5595 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5596 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5599 * Create a new TableBody
5600 * @param {Object} config The config object
5603 Roo.bootstrap.TableBody = function(config){
5604 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5607 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5615 getAutoCreate : function(){
5616 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5630 cfg.align = this.align;
5633 cfg.charoff = this.charoff;
5636 cfg.valign = this.valign;
5643 // initEvents : function()
5650 // this.store = Roo.factory(this.store, Roo.data);
5651 // this.store.on('load', this.onLoad, this);
5653 // this.store.load();
5657 // onLoad: function ()
5659 // this.fireEvent('load', this);
5669 * Ext JS Library 1.1.1
5670 * Copyright(c) 2006-2007, Ext JS, LLC.
5672 * Originally Released Under LGPL - original licence link has changed is not relivant.
5675 * <script type="text/javascript">
5678 // as we use this in bootstrap.
5679 Roo.namespace('Roo.form');
5681 * @class Roo.form.Action
5682 * Internal Class used to handle form actions
5684 * @param {Roo.form.BasicForm} el The form element or its id
5685 * @param {Object} config Configuration options
5690 // define the action interface
5691 Roo.form.Action = function(form, options){
5693 this.options = options || {};
5696 * Client Validation Failed
5699 Roo.form.Action.CLIENT_INVALID = 'client';
5701 * Server Validation Failed
5704 Roo.form.Action.SERVER_INVALID = 'server';
5706 * Connect to Server Failed
5709 Roo.form.Action.CONNECT_FAILURE = 'connect';
5711 * Reading Data from Server Failed
5714 Roo.form.Action.LOAD_FAILURE = 'load';
5716 Roo.form.Action.prototype = {
5718 failureType : undefined,
5719 response : undefined,
5723 run : function(options){
5728 success : function(response){
5733 handleResponse : function(response){
5737 // default connection failure
5738 failure : function(response){
5740 this.response = response;
5741 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5742 this.form.afterAction(this, false);
5745 processResponse : function(response){
5746 this.response = response;
5747 if(!response.responseText){
5750 this.result = this.handleResponse(response);
5754 // utility functions used internally
5755 getUrl : function(appendParams){
5756 var url = this.options.url || this.form.url || this.form.el.dom.action;
5758 var p = this.getParams();
5760 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5766 getMethod : function(){
5767 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5770 getParams : function(){
5771 var bp = this.form.baseParams;
5772 var p = this.options.params;
5774 if(typeof p == "object"){
5775 p = Roo.urlEncode(Roo.applyIf(p, bp));
5776 }else if(typeof p == 'string' && bp){
5777 p += '&' + Roo.urlEncode(bp);
5780 p = Roo.urlEncode(bp);
5785 createCallback : function(){
5787 success: this.success,
5788 failure: this.failure,
5790 timeout: (this.form.timeout*1000),
5791 upload: this.form.fileUpload ? this.success : undefined
5796 Roo.form.Action.Submit = function(form, options){
5797 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
5800 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
5803 haveProgress : false,
5804 uploadComplete : false,
5806 // uploadProgress indicator.
5807 uploadProgress : function()
5809 if (!this.form.progressUrl) {
5813 if (!this.haveProgress) {
5814 Roo.MessageBox.progress("Uploading", "Uploading");
5816 if (this.uploadComplete) {
5817 Roo.MessageBox.hide();
5821 this.haveProgress = true;
5823 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
5825 var c = new Roo.data.Connection();
5827 url : this.form.progressUrl,
5832 success : function(req){
5833 //console.log(data);
5837 rdata = Roo.decode(req.responseText)
5839 Roo.log("Invalid data from server..");
5843 if (!rdata || !rdata.success) {
5845 Roo.MessageBox.alert(Roo.encode(rdata));
5848 var data = rdata.data;
5850 if (this.uploadComplete) {
5851 Roo.MessageBox.hide();
5856 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
5857 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
5860 this.uploadProgress.defer(2000,this);
5863 failure: function(data) {
5864 Roo.log('progress url failed ');
5875 // run get Values on the form, so it syncs any secondary forms.
5876 this.form.getValues();
5878 var o = this.options;
5879 var method = this.getMethod();
5880 var isPost = method == 'POST';
5881 if(o.clientValidation === false || this.form.isValid()){
5883 if (this.form.progressUrl) {
5884 this.form.findField('UPLOAD_IDENTIFIER').setValue(
5885 (new Date() * 1) + '' + Math.random());
5890 Roo.Ajax.request(Roo.apply(this.createCallback(), {
5891 form:this.form.el.dom,
5892 url:this.getUrl(!isPost),
5894 params:isPost ? this.getParams() : null,
5895 isUpload: this.form.fileUpload
5898 this.uploadProgress();
5900 }else if (o.clientValidation !== false){ // client validation failed
5901 this.failureType = Roo.form.Action.CLIENT_INVALID;
5902 this.form.afterAction(this, false);
5906 success : function(response)
5908 this.uploadComplete= true;
5909 if (this.haveProgress) {
5910 Roo.MessageBox.hide();
5914 var result = this.processResponse(response);
5915 if(result === true || result.success){
5916 this.form.afterAction(this, true);
5920 this.form.markInvalid(result.errors);
5921 this.failureType = Roo.form.Action.SERVER_INVALID;
5923 this.form.afterAction(this, false);
5925 failure : function(response)
5927 this.uploadComplete= true;
5928 if (this.haveProgress) {
5929 Roo.MessageBox.hide();
5932 this.response = response;
5933 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5934 this.form.afterAction(this, false);
5937 handleResponse : function(response){
5938 if(this.form.errorReader){
5939 var rs = this.form.errorReader.read(response);
5942 for(var i = 0, len = rs.records.length; i < len; i++) {
5943 var r = rs.records[i];
5947 if(errors.length < 1){
5951 success : rs.success,
5957 ret = Roo.decode(response.responseText);
5961 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
5971 Roo.form.Action.Load = function(form, options){
5972 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
5973 this.reader = this.form.reader;
5976 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
5981 Roo.Ajax.request(Roo.apply(
5982 this.createCallback(), {
5983 method:this.getMethod(),
5984 url:this.getUrl(false),
5985 params:this.getParams()
5989 success : function(response){
5991 var result = this.processResponse(response);
5992 if(result === true || !result.success || !result.data){
5993 this.failureType = Roo.form.Action.LOAD_FAILURE;
5994 this.form.afterAction(this, false);
5997 this.form.clearInvalid();
5998 this.form.setValues(result.data);
5999 this.form.afterAction(this, true);
6002 handleResponse : function(response){
6003 if(this.form.reader){
6004 var rs = this.form.reader.read(response);
6005 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6007 success : rs.success,
6011 return Roo.decode(response.responseText);
6015 Roo.form.Action.ACTION_TYPES = {
6016 'load' : Roo.form.Action.Load,
6017 'submit' : Roo.form.Action.Submit
6026 * @class Roo.bootstrap.Form
6027 * @extends Roo.bootstrap.Component
6028 * Bootstrap Form class
6029 * @cfg {String} method GET | POST (default POST)
6030 * @cfg {String} labelAlign top | left (default top)
6031 * @cfg {String} align left | right - for navbars
6036 * @param {Object} config The config object
6040 Roo.bootstrap.Form = function(config){
6041 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6044 * @event clientvalidation
6045 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6046 * @param {Form} this
6047 * @param {Boolean} valid true if the form has passed client-side validation
6049 clientvalidation: true,
6051 * @event beforeaction
6052 * Fires before any action is performed. Return false to cancel the action.
6053 * @param {Form} this
6054 * @param {Action} action The action to be performed
6058 * @event actionfailed
6059 * Fires when an action fails.
6060 * @param {Form} this
6061 * @param {Action} action The action that failed
6063 actionfailed : true,
6065 * @event actioncomplete
6066 * Fires when an action is completed.
6067 * @param {Form} this
6068 * @param {Action} action The action that completed
6070 actioncomplete : true
6075 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6078 * @cfg {String} method
6079 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6084 * The URL to use for form actions if one isn't supplied in the action options.
6087 * @cfg {Boolean} fileUpload
6088 * Set to true if this form is a file upload.
6092 * @cfg {Object} baseParams
6093 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6097 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6101 * @cfg {Sting} align (left|right) for navbar forms
6106 activeAction : null,
6109 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6110 * element by passing it or its id or mask the form itself by passing in true.
6113 waitMsgTarget : false,
6118 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6119 * element by passing it or its id or mask the form itself by passing in true.
6123 getAutoCreate : function(){
6127 method : this.method || 'POST',
6128 id : this.id || Roo.id(),
6131 if (this.parent().xtype.match(/^Nav/)) {
6132 cfg.cls = 'navbar-form navbar-' + this.align;
6136 if (this.labelAlign == 'left' ) {
6137 cfg.cls += ' form-horizontal';
6143 initEvents : function()
6145 this.el.on('submit', this.onSubmit, this);
6146 // this was added as random key presses on the form where triggering form submit.
6147 this.el.on('keypress', function(e) {
6148 if (e.getCharCode() != 13) {
6151 // we might need to allow it for textareas.. and some other items.
6152 // check e.getTarget().
6154 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6158 Roo.log("keypress blocked");
6166 onSubmit : function(e){
6171 * Returns true if client-side validation on the form is successful.
6174 isValid : function(){
6175 var items = this.getItems();
6177 items.each(function(f){
6186 * Returns true if any fields in this form have changed since their original load.
6189 isDirty : function(){
6191 var items = this.getItems();
6192 items.each(function(f){
6202 * Performs a predefined action (submit or load) or custom actions you define on this form.
6203 * @param {String} actionName The name of the action type
6204 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6205 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6206 * accept other config options):
6208 Property Type Description
6209 ---------------- --------------- ----------------------------------------------------------------------------------
6210 url String The url for the action (defaults to the form's url)
6211 method String The form method to use (defaults to the form's method, or POST if not defined)
6212 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6213 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6214 validate the form on the client (defaults to false)
6216 * @return {BasicForm} this
6218 doAction : function(action, options){
6219 if(typeof action == 'string'){
6220 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6222 if(this.fireEvent('beforeaction', this, action) !== false){
6223 this.beforeAction(action);
6224 action.run.defer(100, action);
6230 beforeAction : function(action){
6231 var o = action.options;
6233 // not really supported yet.. ??
6235 //if(this.waitMsgTarget === true){
6236 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6237 //}else if(this.waitMsgTarget){
6238 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6239 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6241 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6247 afterAction : function(action, success){
6248 this.activeAction = null;
6249 var o = action.options;
6251 //if(this.waitMsgTarget === true){
6253 //}else if(this.waitMsgTarget){
6254 // this.waitMsgTarget.unmask();
6256 // Roo.MessageBox.updateProgress(1);
6257 // Roo.MessageBox.hide();
6264 Roo.callback(o.success, o.scope, [this, action]);
6265 this.fireEvent('actioncomplete', this, action);
6269 // failure condition..
6270 // we have a scenario where updates need confirming.
6271 // eg. if a locking scenario exists..
6272 // we look for { errors : { needs_confirm : true }} in the response.
6274 (typeof(action.result) != 'undefined') &&
6275 (typeof(action.result.errors) != 'undefined') &&
6276 (typeof(action.result.errors.needs_confirm) != 'undefined')
6279 Roo.log("not supported yet");
6282 Roo.MessageBox.confirm(
6283 "Change requires confirmation",
6284 action.result.errorMsg,
6289 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6299 Roo.callback(o.failure, o.scope, [this, action]);
6300 // show an error message if no failed handler is set..
6301 if (!this.hasListener('actionfailed')) {
6302 Roo.log("need to add dialog support");
6304 Roo.MessageBox.alert("Error",
6305 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6306 action.result.errorMsg :
6307 "Saving Failed, please check your entries or try again"
6312 this.fireEvent('actionfailed', this, action);
6317 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6318 * @param {String} id The value to search for
6321 findField : function(id){
6322 var items = this.getItems();
6323 var field = items.get(id);
6325 items.each(function(f){
6326 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6333 return field || null;
6336 * Mark fields in this form invalid in bulk.
6337 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6338 * @return {BasicForm} this
6340 markInvalid : function(errors){
6341 if(errors instanceof Array){
6342 for(var i = 0, len = errors.length; i < len; i++){
6343 var fieldError = errors[i];
6344 var f = this.findField(fieldError.id);
6346 f.markInvalid(fieldError.msg);
6352 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6353 field.markInvalid(errors[id]);
6357 //Roo.each(this.childForms || [], function (f) {
6358 // f.markInvalid(errors);
6365 * Set values for fields in this form in bulk.
6366 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6367 * @return {BasicForm} this
6369 setValues : function(values){
6370 if(values instanceof Array){ // array of objects
6371 for(var i = 0, len = values.length; i < len; i++){
6373 var f = this.findField(v.id);
6375 f.setValue(v.value);
6376 if(this.trackResetOnLoad){
6377 f.originalValue = f.getValue();
6381 }else{ // object hash
6384 if(typeof values[id] != 'function' && (field = this.findField(id))){
6386 if (field.setFromData &&
6388 field.displayField &&
6389 // combos' with local stores can
6390 // be queried via setValue()
6391 // to set their value..
6392 (field.store && !field.store.isLocal)
6396 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6397 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6398 field.setFromData(sd);
6401 field.setValue(values[id]);
6405 if(this.trackResetOnLoad){
6406 field.originalValue = field.getValue();
6412 //Roo.each(this.childForms || [], function (f) {
6413 // f.setValues(values);
6420 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6421 * they are returned as an array.
6422 * @param {Boolean} asString
6425 getValues : function(asString){
6426 //if (this.childForms) {
6427 // copy values from the child forms
6428 // Roo.each(this.childForms, function (f) {
6429 // this.setValues(f.getValues());
6435 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6436 if(asString === true){
6439 return Roo.urlDecode(fs);
6443 * Returns the fields in this form as an object with key/value pairs.
6444 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6447 getFieldValues : function(with_hidden)
6449 var items = this.getItems();
6451 items.each(function(f){
6455 var v = f.getValue();
6456 if (f.inputType =='radio') {
6457 if (typeof(ret[f.getName()]) == 'undefined') {
6458 ret[f.getName()] = ''; // empty..
6461 if (!f.el.dom.checked) {
6469 // not sure if this supported any more..
6470 if ((typeof(v) == 'object') && f.getRawValue) {
6471 v = f.getRawValue() ; // dates..
6473 // combo boxes where name != hiddenName...
6474 if (f.name != f.getName()) {
6475 ret[f.name] = f.getRawValue();
6477 ret[f.getName()] = v;
6484 * Clears all invalid messages in this form.
6485 * @return {BasicForm} this
6487 clearInvalid : function(){
6488 var items = this.getItems();
6490 items.each(function(f){
6501 * @return {BasicForm} this
6504 var items = this.getItems();
6505 items.each(function(f){
6509 Roo.each(this.childForms || [], function (f) {
6516 getItems : function()
6518 var r=new Roo.util.MixedCollection(false, function(o){
6519 return o.id || (o.id = Roo.id());
6521 var iter = function(el) {
6528 Roo.each(el.items,function(e) {
6547 * Ext JS Library 1.1.1
6548 * Copyright(c) 2006-2007, Ext JS, LLC.
6550 * Originally Released Under LGPL - original licence link has changed is not relivant.
6553 * <script type="text/javascript">
6556 * @class Roo.form.VTypes
6557 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6560 Roo.form.VTypes = function(){
6561 // closure these in so they are only created once.
6562 var alpha = /^[a-zA-Z_]+$/;
6563 var alphanum = /^[a-zA-Z0-9_]+$/;
6564 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6565 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6567 // All these messages and functions are configurable
6570 * The function used to validate email addresses
6571 * @param {String} value The email address
6573 'email' : function(v){
6574 return email.test(v);
6577 * The error text to display when the email validation function returns false
6580 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6582 * The keystroke filter mask to be applied on email input
6585 'emailMask' : /[a-z0-9_\.\-@]/i,
6588 * The function used to validate URLs
6589 * @param {String} value The URL
6591 'url' : function(v){
6595 * The error text to display when the url validation function returns false
6598 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6601 * The function used to validate alpha values
6602 * @param {String} value The value
6604 'alpha' : function(v){
6605 return alpha.test(v);
6608 * The error text to display when the alpha validation function returns false
6611 'alphaText' : 'This field should only contain letters and _',
6613 * The keystroke filter mask to be applied on alpha input
6616 'alphaMask' : /[a-z_]/i,
6619 * The function used to validate alphanumeric values
6620 * @param {String} value The value
6622 'alphanum' : function(v){
6623 return alphanum.test(v);
6626 * The error text to display when the alphanumeric validation function returns false
6629 'alphanumText' : 'This field should only contain letters, numbers and _',
6631 * The keystroke filter mask to be applied on alphanumeric input
6634 'alphanumMask' : /[a-z0-9_]/i
6644 * @class Roo.bootstrap.Input
6645 * @extends Roo.bootstrap.Component
6646 * Bootstrap Input class
6647 * @cfg {Boolean} disabled is it disabled
6648 * @cfg {String} fieldLabel - the label associated
6649 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6650 * @cfg {String} name name of the input
6651 * @cfg {string} fieldLabel - the label associated
6652 * @cfg {string} inputType - input / file submit ...
6653 * @cfg {string} placeholder - placeholder to put in text.
6654 * @cfg {string} before - input group add on before
6655 * @cfg {string} after - input group add on after
6656 * @cfg {string} size - (lg|sm) or leave empty..
6657 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6658 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6659 * @cfg {Number} md colspan out of 12 for computer-sized screens
6660 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6661 * @cfg {string} value default value of the input
6662 * @cfg {Number} labelWidth set the width of label (0-12)
6663 * @cfg {String} labelAlign (top|left)
6664 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6665 * @cfg {String} align (left|center|right) Default left
6669 * Create a new Input
6670 * @param {Object} config The config object
6673 Roo.bootstrap.Input = function(config){
6674 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6679 * Fires when this field receives input focus.
6680 * @param {Roo.form.Field} this
6685 * Fires when this field loses input focus.
6686 * @param {Roo.form.Field} this
6691 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6692 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6693 * @param {Roo.form.Field} this
6694 * @param {Roo.EventObject} e The event object
6699 * Fires just before the field blurs if the field value has changed.
6700 * @param {Roo.form.Field} this
6701 * @param {Mixed} newValue The new value
6702 * @param {Mixed} oldValue The original value
6707 * Fires after the field has been marked as invalid.
6708 * @param {Roo.form.Field} this
6709 * @param {String} msg The validation message
6714 * Fires after the field has been validated with no errors.
6715 * @param {Roo.form.Field} this
6720 * Fires after the key up
6721 * @param {Roo.form.Field} this
6722 * @param {Roo.EventObject} e The event Object
6728 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6730 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6731 automatic validation (defaults to "keyup").
6733 validationEvent : "keyup",
6735 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6737 validateOnBlur : true,
6739 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6741 validationDelay : 250,
6743 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6745 focusClass : "x-form-focus", // not needed???
6749 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6751 invalidClass : "has-error",
6754 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6756 selectOnFocus : false,
6759 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6763 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6768 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6770 disableKeyFilter : false,
6773 * @cfg {Boolean} disabled True to disable the field (defaults to false).
6777 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6781 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6783 blankText : "This field is required",
6786 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
6790 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
6792 maxLength : Number.MAX_VALUE,
6794 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
6796 minLengthText : "The minimum length for this field is {0}",
6798 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
6800 maxLengthText : "The maximum length for this field is {0}",
6804 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
6805 * If available, this function will be called only after the basic validators all return true, and will be passed the
6806 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
6810 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
6811 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
6812 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
6816 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
6839 formatedValue : false,
6841 parentLabelAlign : function()
6844 while (parent.parent()) {
6845 parent = parent.parent();
6846 if (typeof(parent.labelAlign) !='undefined') {
6847 return parent.labelAlign;
6854 getAutoCreate : function(){
6856 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6862 if(this.inputType != 'hidden'){
6863 cfg.cls = 'form-group' //input-group
6869 type : this.inputType,
6871 cls : 'form-control',
6872 placeholder : this.placeholder || ''
6877 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
6880 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6881 input.maxLength = this.maxLength;
6884 if (this.disabled) {
6885 input.disabled=true;
6888 if (this.readOnly) {
6889 input.readonly=true;
6893 input.name = this.name;
6896 input.cls += ' input-' + this.size;
6899 ['xs','sm','md','lg'].map(function(size){
6900 if (settings[size]) {
6901 cfg.cls += ' col-' + size + '-' + settings[size];
6905 var inputblock = input;
6907 if (this.before || this.after) {
6910 cls : 'input-group',
6913 if (this.before && typeof(this.before) == 'string') {
6915 inputblock.cn.push({
6917 cls : 'roo-input-before input-group-addon',
6921 if (this.before && typeof(this.before) == 'object') {
6922 this.before = Roo.factory(this.before);
6923 Roo.log(this.before);
6924 inputblock.cn.push({
6926 cls : 'roo-input-before input-group-' +
6927 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6931 inputblock.cn.push(input);
6933 if (this.after && typeof(this.after) == 'string') {
6934 inputblock.cn.push({
6936 cls : 'roo-input-after input-group-addon',
6940 if (this.after && typeof(this.after) == 'object') {
6941 this.after = Roo.factory(this.after);
6942 Roo.log(this.after);
6943 inputblock.cn.push({
6945 cls : 'roo-input-after input-group-' +
6946 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6951 if (align ==='left' && this.fieldLabel.length) {
6952 Roo.log("left and has label");
6958 cls : 'control-label col-sm-' + this.labelWidth,
6959 html : this.fieldLabel
6963 cls : "col-sm-" + (12 - this.labelWidth),
6970 } else if ( this.fieldLabel.length) {
6976 //cls : 'input-group-addon',
6977 html : this.fieldLabel
6987 Roo.log(" no label && no align");
6996 Roo.log('input-parentType: ' + this.parentType);
6998 if (this.parentType === 'Navbar' && this.parent().bar) {
6999 cfg.cls += ' navbar-form';
7007 * return the real input element.
7009 inputEl: function ()
7011 return this.el.select('input.form-control',true).first();
7013 setDisabled : function(v)
7015 var i = this.inputEl().dom;
7017 i.removeAttribute('disabled');
7021 i.setAttribute('disabled','true');
7023 initEvents : function()
7026 this.inputEl().on("keydown" , this.fireKey, this);
7027 this.inputEl().on("focus", this.onFocus, this);
7028 this.inputEl().on("blur", this.onBlur, this);
7030 this.inputEl().relayEvent('keyup', this);
7032 // reference to original value for reset
7033 this.originalValue = this.getValue();
7034 //Roo.form.TextField.superclass.initEvents.call(this);
7035 if(this.validationEvent == 'keyup'){
7036 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7037 this.inputEl().on('keyup', this.filterValidation, this);
7039 else if(this.validationEvent !== false){
7040 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7043 if(this.selectOnFocus){
7044 this.on("focus", this.preFocus, this);
7047 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7048 this.inputEl().on("keypress", this.filterKeys, this);
7051 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7052 this.el.on("click", this.autoSize, this);
7055 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7056 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7059 if (typeof(this.before) == 'object') {
7060 this.before.render(this.el.select('.roo-input-before',true).first());
7062 if (typeof(this.after) == 'object') {
7063 this.after.render(this.el.select('.roo-input-after',true).first());
7068 filterValidation : function(e){
7069 if(!e.isNavKeyPress()){
7070 this.validationTask.delay(this.validationDelay);
7074 * Validates the field value
7075 * @return {Boolean} True if the value is valid, else false
7077 validate : function(){
7078 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7079 if(this.disabled || this.validateValue(this.getRawValue())){
7080 this.clearInvalid();
7088 * Validates a value according to the field's validation rules and marks the field as invalid
7089 * if the validation fails
7090 * @param {Mixed} value The value to validate
7091 * @return {Boolean} True if the value is valid, else false
7093 validateValue : function(value){
7094 if(value.length < 1) { // if it's blank
7095 if(this.allowBlank){
7096 this.clearInvalid();
7099 this.markInvalid(this.blankText);
7103 if(value.length < this.minLength){
7104 this.markInvalid(String.format(this.minLengthText, this.minLength));
7107 if(value.length > this.maxLength){
7108 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
7112 var vt = Roo.form.VTypes;
7113 if(!vt[this.vtype](value, this)){
7114 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
7118 if(typeof this.validator == "function"){
7119 var msg = this.validator(value);
7121 this.markInvalid(msg);
7125 if(this.regex && !this.regex.test(value)){
7126 this.markInvalid(this.regexText);
7135 fireKey : function(e){
7136 //Roo.log('field ' + e.getKey());
7137 if(e.isNavKeyPress()){
7138 this.fireEvent("specialkey", this, e);
7141 focus : function (selectText){
7143 this.inputEl().focus();
7144 if(selectText === true){
7145 this.inputEl().dom.select();
7151 onFocus : function(){
7152 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7153 // this.el.addClass(this.focusClass);
7156 this.hasFocus = true;
7157 this.startValue = this.getValue();
7158 this.fireEvent("focus", this);
7162 beforeBlur : Roo.emptyFn,
7166 onBlur : function(){
7168 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7169 //this.el.removeClass(this.focusClass);
7171 this.hasFocus = false;
7172 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7175 var v = this.getValue();
7176 if(String(v) !== String(this.startValue)){
7177 this.fireEvent('change', this, v, this.startValue);
7179 this.fireEvent("blur", this);
7183 * Resets the current field value to the originally loaded value and clears any validation messages
7186 this.setValue(this.originalValue);
7187 this.clearInvalid();
7190 * Returns the name of the field
7191 * @return {Mixed} name The name field
7193 getName: function(){
7197 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7198 * @return {Mixed} value The field value
7200 getValue : function(){
7202 var v = this.inputEl().getValue();
7207 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7208 * @return {Mixed} value The field value
7210 getRawValue : function(){
7211 var v = this.inputEl().getValue();
7217 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7218 * @param {Mixed} value The value to set
7220 setRawValue : function(v){
7221 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7224 selectText : function(start, end){
7225 var v = this.getRawValue();
7227 start = start === undefined ? 0 : start;
7228 end = end === undefined ? v.length : end;
7229 var d = this.inputEl().dom;
7230 if(d.setSelectionRange){
7231 d.setSelectionRange(start, end);
7232 }else if(d.createTextRange){
7233 var range = d.createTextRange();
7234 range.moveStart("character", start);
7235 range.moveEnd("character", v.length-end);
7242 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7243 * @param {Mixed} value The value to set
7245 setValue : function(v){
7248 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7254 processValue : function(value){
7255 if(this.stripCharsRe){
7256 var newValue = value.replace(this.stripCharsRe, '');
7257 if(newValue !== value){
7258 this.setRawValue(newValue);
7265 preFocus : function(){
7267 if(this.selectOnFocus){
7268 this.inputEl().dom.select();
7271 filterKeys : function(e){
7273 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7276 var c = e.getCharCode(), cc = String.fromCharCode(c);
7277 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7280 if(!this.maskRe.test(cc)){
7285 * Clear any invalid styles/messages for this field
7287 clearInvalid : function(){
7289 if(!this.el || this.preventMark){ // not rendered
7292 this.el.removeClass(this.invalidClass);
7294 switch(this.msgTarget){
7296 this.el.dom.qtip = '';
7299 this.el.dom.title = '';
7303 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7308 this.errorIcon.dom.qtip = '';
7309 this.errorIcon.hide();
7310 this.un('resize', this.alignErrorIcon, this);
7314 var t = Roo.getDom(this.msgTarget);
7316 t.style.display = 'none';
7320 this.fireEvent('valid', this);
7323 * Mark this field as invalid
7324 * @param {String} msg The validation message
7326 markInvalid : function(msg){
7327 if(!this.el || this.preventMark){ // not rendered
7330 this.el.addClass(this.invalidClass);
7332 msg = msg || this.invalidText;
7333 switch(this.msgTarget){
7335 this.el.dom.qtip = msg;
7336 this.el.dom.qclass = 'x-form-invalid-tip';
7337 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7338 Roo.QuickTips.enable();
7342 this.el.dom.title = msg;
7346 var elp = this.el.findParent('.x-form-element', 5, true);
7347 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7348 this.errorEl.setWidth(elp.getWidth(true)-20);
7350 this.errorEl.update(msg);
7351 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7354 if(!this.errorIcon){
7355 var elp = this.el.findParent('.x-form-element', 5, true);
7356 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7358 this.alignErrorIcon();
7359 this.errorIcon.dom.qtip = msg;
7360 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7361 this.errorIcon.show();
7362 this.on('resize', this.alignErrorIcon, this);
7365 var t = Roo.getDom(this.msgTarget);
7367 t.style.display = this.msgDisplay;
7371 this.fireEvent('invalid', this, msg);
7374 SafariOnKeyDown : function(event)
7376 // this is a workaround for a password hang bug on chrome/ webkit.
7378 var isSelectAll = false;
7380 if(this.inputEl().dom.selectionEnd > 0){
7381 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7383 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7384 event.preventDefault();
7389 if(isSelectAll){ // backspace and delete key
7391 event.preventDefault();
7392 // this is very hacky as keydown always get's upper case.
7394 var cc = String.fromCharCode(event.getCharCode());
7395 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7399 adjustWidth : function(tag, w){
7400 tag = tag.toLowerCase();
7401 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7402 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7406 if(tag == 'textarea'){
7409 }else if(Roo.isOpera){
7413 if(tag == 'textarea'){
7432 * @class Roo.bootstrap.TextArea
7433 * @extends Roo.bootstrap.Input
7434 * Bootstrap TextArea class
7435 * @cfg {Number} cols Specifies the visible width of a text area
7436 * @cfg {Number} rows Specifies the visible number of lines in a text area
7437 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7438 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7439 * @cfg {string} html text
7442 * Create a new TextArea
7443 * @param {Object} config The config object
7446 Roo.bootstrap.TextArea = function(config){
7447 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7451 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7461 getAutoCreate : function(){
7463 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7474 value : this.value || '',
7475 html: this.html || '',
7476 cls : 'form-control',
7477 placeholder : this.placeholder || ''
7481 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7482 input.maxLength = this.maxLength;
7486 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7490 input.cols = this.cols;
7493 if (this.readOnly) {
7494 input.readonly = true;
7498 input.name = this.name;
7502 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7506 ['xs','sm','md','lg'].map(function(size){
7507 if (settings[size]) {
7508 cfg.cls += ' col-' + size + '-' + settings[size];
7512 var inputblock = input;
7514 if (this.before || this.after) {
7517 cls : 'input-group',
7521 inputblock.cn.push({
7523 cls : 'input-group-addon',
7527 inputblock.cn.push(input);
7529 inputblock.cn.push({
7531 cls : 'input-group-addon',
7538 if (align ==='left' && this.fieldLabel.length) {
7539 Roo.log("left and has label");
7545 cls : 'control-label col-sm-' + this.labelWidth,
7546 html : this.fieldLabel
7550 cls : "col-sm-" + (12 - this.labelWidth),
7557 } else if ( this.fieldLabel.length) {
7563 //cls : 'input-group-addon',
7564 html : this.fieldLabel
7574 Roo.log(" no label && no align");
7584 if (this.disabled) {
7585 input.disabled=true;
7592 * return the real textarea element.
7594 inputEl: function ()
7596 return this.el.select('textarea.form-control',true).first();
7604 * trigger field - base class for combo..
7609 * @class Roo.bootstrap.TriggerField
7610 * @extends Roo.bootstrap.Input
7611 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7612 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7613 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7614 * for which you can provide a custom implementation. For example:
7616 var trigger = new Roo.bootstrap.TriggerField();
7617 trigger.onTriggerClick = myTriggerFn;
7618 trigger.applyTo('my-field');
7621 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7622 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7623 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7624 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7626 * Create a new TriggerField.
7627 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7628 * to the base TextField)
7630 Roo.bootstrap.TriggerField = function(config){
7631 this.mimicing = false;
7632 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7635 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7637 * @cfg {String} triggerClass A CSS class to apply to the trigger
7640 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7644 /** @cfg {Boolean} grow @hide */
7645 /** @cfg {Number} growMin @hide */
7646 /** @cfg {Number} growMax @hide */
7652 autoSize: Roo.emptyFn,
7659 actionMode : 'wrap',
7663 getAutoCreate : function(){
7665 var align = this.labelAlign || this.parentLabelAlign();
7670 cls: 'form-group' //input-group
7677 type : this.inputType,
7678 cls : 'form-control',
7679 autocomplete: 'off',
7680 placeholder : this.placeholder || ''
7684 input.name = this.name;
7687 input.cls += ' input-' + this.size;
7690 if (this.disabled) {
7691 input.disabled=true;
7694 var inputblock = input;
7696 if (this.before || this.after) {
7699 cls : 'input-group',
7703 inputblock.cn.push({
7705 cls : 'input-group-addon',
7709 inputblock.cn.push(input);
7711 inputblock.cn.push({
7713 cls : 'input-group-addon',
7726 cls: 'form-hidden-field'
7734 Roo.log('multiple');
7742 cls: 'form-hidden-field'
7746 cls: 'select2-choices',
7750 cls: 'select2-search-field',
7763 cls: 'select2-container input-group',
7768 // cls: 'typeahead typeahead-long dropdown-menu',
7769 // style: 'display:none'
7777 cls : 'input-group-addon btn dropdown-toggle',
7785 cls: 'combobox-clear',
7799 combobox.cls += ' select2-container-multi';
7802 if (align ==='left' && this.fieldLabel.length) {
7804 Roo.log("left and has label");
7810 cls : 'control-label col-sm-' + this.labelWidth,
7811 html : this.fieldLabel
7815 cls : "col-sm-" + (12 - this.labelWidth),
7822 } else if ( this.fieldLabel.length) {
7828 //cls : 'input-group-addon',
7829 html : this.fieldLabel
7839 Roo.log(" no label && no align");
7846 ['xs','sm','md','lg'].map(function(size){
7847 if (settings[size]) {
7848 cfg.cls += ' col-' + size + '-' + settings[size];
7859 onResize : function(w, h){
7860 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
7861 // if(typeof w == 'number'){
7862 // var x = w - this.trigger.getWidth();
7863 // this.inputEl().setWidth(this.adjustWidth('input', x));
7864 // this.trigger.setStyle('left', x+'px');
7869 adjustSize : Roo.BoxComponent.prototype.adjustSize,
7872 getResizeEl : function(){
7873 return this.inputEl();
7877 getPositionEl : function(){
7878 return this.inputEl();
7882 alignErrorIcon : function(){
7883 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
7887 initEvents : function(){
7891 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
7892 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
7894 this.trigger = this.el.select('span.dropdown-toggle',true).first();
7895 if(this.hideTrigger){
7896 this.trigger.setDisplayed(false);
7898 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
7902 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
7905 //this.trigger.addClassOnOver('x-form-trigger-over');
7906 //this.trigger.addClassOnClick('x-form-trigger-click');
7909 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
7913 createList : function()
7915 this.list = Roo.get(document.body).createChild({
7917 cls: 'typeahead typeahead-long dropdown-menu',
7918 style: 'display:none'
7923 initTrigger : function(){
7928 onDestroy : function(){
7930 this.trigger.removeAllListeners();
7931 // this.trigger.remove();
7934 // this.wrap.remove();
7936 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
7940 onFocus : function(){
7941 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
7944 this.wrap.addClass('x-trigger-wrap-focus');
7945 this.mimicing = true;
7946 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
7947 if(this.monitorTab){
7948 this.el.on("keydown", this.checkTab, this);
7955 checkTab : function(e){
7956 if(e.getKey() == e.TAB){
7962 onBlur : function(){
7967 mimicBlur : function(e, t){
7969 if(!this.wrap.contains(t) && this.validateBlur()){
7976 triggerBlur : function(){
7977 this.mimicing = false;
7978 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
7979 if(this.monitorTab){
7980 this.el.un("keydown", this.checkTab, this);
7982 //this.wrap.removeClass('x-trigger-wrap-focus');
7983 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
7987 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
7988 validateBlur : function(e, t){
7993 onDisable : function(){
7994 this.inputEl().dom.disabled = true;
7995 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
7997 // this.wrap.addClass('x-item-disabled');
8002 onEnable : function(){
8003 this.inputEl().dom.disabled = false;
8004 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8006 // this.el.removeClass('x-item-disabled');
8011 onShow : function(){
8012 var ae = this.getActionEl();
8015 ae.dom.style.display = '';
8016 ae.dom.style.visibility = 'visible';
8022 onHide : function(){
8023 var ae = this.getActionEl();
8024 ae.dom.style.display = 'none';
8028 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8029 * by an implementing function.
8031 * @param {EventObject} e
8033 onTriggerClick : Roo.emptyFn
8037 * Ext JS Library 1.1.1
8038 * Copyright(c) 2006-2007, Ext JS, LLC.
8040 * Originally Released Under LGPL - original licence link has changed is not relivant.
8043 * <script type="text/javascript">
8048 * @class Roo.data.SortTypes
8050 * Defines the default sorting (casting?) comparison functions used when sorting data.
8052 Roo.data.SortTypes = {
8054 * Default sort that does nothing
8055 * @param {Mixed} s The value being converted
8056 * @return {Mixed} The comparison value
8063 * The regular expression used to strip tags
8067 stripTagsRE : /<\/?[^>]+>/gi,
8070 * Strips all HTML tags to sort on text only
8071 * @param {Mixed} s The value being converted
8072 * @return {String} The comparison value
8074 asText : function(s){
8075 return String(s).replace(this.stripTagsRE, "");
8079 * Strips all HTML tags to sort on text only - Case insensitive
8080 * @param {Mixed} s The value being converted
8081 * @return {String} The comparison value
8083 asUCText : function(s){
8084 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8088 * Case insensitive string
8089 * @param {Mixed} s The value being converted
8090 * @return {String} The comparison value
8092 asUCString : function(s) {
8093 return String(s).toUpperCase();
8098 * @param {Mixed} s The value being converted
8099 * @return {Number} The comparison value
8101 asDate : function(s) {
8105 if(s instanceof Date){
8108 return Date.parse(String(s));
8113 * @param {Mixed} s The value being converted
8114 * @return {Float} The comparison value
8116 asFloat : function(s) {
8117 var val = parseFloat(String(s).replace(/,/g, ""));
8118 if(isNaN(val)) val = 0;
8124 * @param {Mixed} s The value being converted
8125 * @return {Number} The comparison value
8127 asInt : function(s) {
8128 var val = parseInt(String(s).replace(/,/g, ""));
8129 if(isNaN(val)) val = 0;
8134 * Ext JS Library 1.1.1
8135 * Copyright(c) 2006-2007, Ext JS, LLC.
8137 * Originally Released Under LGPL - original licence link has changed is not relivant.
8140 * <script type="text/javascript">
8144 * @class Roo.data.Record
8145 * Instances of this class encapsulate both record <em>definition</em> information, and record
8146 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8147 * to access Records cached in an {@link Roo.data.Store} object.<br>
8149 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8150 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8153 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8155 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8156 * {@link #create}. The parameters are the same.
8157 * @param {Array} data An associative Array of data values keyed by the field name.
8158 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8159 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8160 * not specified an integer id is generated.
8162 Roo.data.Record = function(data, id){
8163 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8168 * Generate a constructor for a specific record layout.
8169 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8170 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8171 * Each field definition object may contain the following properties: <ul>
8172 * <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,
8173 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8174 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8175 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8176 * is being used, then this is a string containing the javascript expression to reference the data relative to
8177 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8178 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8179 * this may be omitted.</p></li>
8180 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8181 * <ul><li>auto (Default, implies no conversion)</li>
8186 * <li>date</li></ul></p></li>
8187 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8188 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8189 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8190 * by the Reader into an object that will be stored in the Record. It is passed the
8191 * following parameters:<ul>
8192 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8194 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8196 * <br>usage:<br><pre><code>
8197 var TopicRecord = Roo.data.Record.create(
8198 {name: 'title', mapping: 'topic_title'},
8199 {name: 'author', mapping: 'username'},
8200 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8201 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8202 {name: 'lastPoster', mapping: 'user2'},
8203 {name: 'excerpt', mapping: 'post_text'}
8206 var myNewRecord = new TopicRecord({
8207 title: 'Do my job please',
8210 lastPost: new Date(),
8211 lastPoster: 'Animal',
8212 excerpt: 'No way dude!'
8214 myStore.add(myNewRecord);
8219 Roo.data.Record.create = function(o){
8221 f.superclass.constructor.apply(this, arguments);
8223 Roo.extend(f, Roo.data.Record);
8224 var p = f.prototype;
8225 p.fields = new Roo.util.MixedCollection(false, function(field){
8228 for(var i = 0, len = o.length; i < len; i++){
8229 p.fields.add(new Roo.data.Field(o[i]));
8231 f.getField = function(name){
8232 return p.fields.get(name);
8237 Roo.data.Record.AUTO_ID = 1000;
8238 Roo.data.Record.EDIT = 'edit';
8239 Roo.data.Record.REJECT = 'reject';
8240 Roo.data.Record.COMMIT = 'commit';
8242 Roo.data.Record.prototype = {
8244 * Readonly flag - true if this record has been modified.
8253 join : function(store){
8258 * Set the named field to the specified value.
8259 * @param {String} name The name of the field to set.
8260 * @param {Object} value The value to set the field to.
8262 set : function(name, value){
8263 if(this.data[name] == value){
8270 if(typeof this.modified[name] == 'undefined'){
8271 this.modified[name] = this.data[name];
8273 this.data[name] = value;
8274 if(!this.editing && this.store){
8275 this.store.afterEdit(this);
8280 * Get the value of the named field.
8281 * @param {String} name The name of the field to get the value of.
8282 * @return {Object} The value of the field.
8284 get : function(name){
8285 return this.data[name];
8289 beginEdit : function(){
8290 this.editing = true;
8295 cancelEdit : function(){
8296 this.editing = false;
8297 delete this.modified;
8301 endEdit : function(){
8302 this.editing = false;
8303 if(this.dirty && this.store){
8304 this.store.afterEdit(this);
8309 * Usually called by the {@link Roo.data.Store} which owns the Record.
8310 * Rejects all changes made to the Record since either creation, or the last commit operation.
8311 * Modified fields are reverted to their original values.
8313 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8314 * of reject operations.
8316 reject : function(){
8317 var m = this.modified;
8319 if(typeof m[n] != "function"){
8320 this.data[n] = m[n];
8324 delete this.modified;
8325 this.editing = false;
8327 this.store.afterReject(this);
8332 * Usually called by the {@link Roo.data.Store} which owns the Record.
8333 * Commits all changes made to the Record since either creation, or the last commit operation.
8335 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8336 * of commit operations.
8338 commit : function(){
8340 delete this.modified;
8341 this.editing = false;
8343 this.store.afterCommit(this);
8348 hasError : function(){
8349 return this.error != null;
8353 clearError : function(){
8358 * Creates a copy of this record.
8359 * @param {String} id (optional) A new record id if you don't want to use this record's id
8362 copy : function(newId) {
8363 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8367 * Ext JS Library 1.1.1
8368 * Copyright(c) 2006-2007, Ext JS, LLC.
8370 * Originally Released Under LGPL - original licence link has changed is not relivant.
8373 * <script type="text/javascript">
8379 * @class Roo.data.Store
8380 * @extends Roo.util.Observable
8381 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8382 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8384 * 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
8385 * has no knowledge of the format of the data returned by the Proxy.<br>
8387 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8388 * instances from the data object. These records are cached and made available through accessor functions.
8390 * Creates a new Store.
8391 * @param {Object} config A config object containing the objects needed for the Store to access data,
8392 * and read the data into Records.
8394 Roo.data.Store = function(config){
8395 this.data = new Roo.util.MixedCollection(false);
8396 this.data.getKey = function(o){
8399 this.baseParams = {};
8406 "multisort" : "_multisort"
8409 if(config && config.data){
8410 this.inlineData = config.data;
8414 Roo.apply(this, config);
8416 if(this.reader){ // reader passed
8417 this.reader = Roo.factory(this.reader, Roo.data);
8418 this.reader.xmodule = this.xmodule || false;
8419 if(!this.recordType){
8420 this.recordType = this.reader.recordType;
8422 if(this.reader.onMetaChange){
8423 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8427 if(this.recordType){
8428 this.fields = this.recordType.prototype.fields;
8434 * @event datachanged
8435 * Fires when the data cache has changed, and a widget which is using this Store
8436 * as a Record cache should refresh its view.
8437 * @param {Store} this
8442 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8443 * @param {Store} this
8444 * @param {Object} meta The JSON metadata
8449 * Fires when Records have been added to the Store
8450 * @param {Store} this
8451 * @param {Roo.data.Record[]} records The array of Records added
8452 * @param {Number} index The index at which the record(s) were added
8457 * Fires when a Record has been removed from the Store
8458 * @param {Store} this
8459 * @param {Roo.data.Record} record The Record that was removed
8460 * @param {Number} index The index at which the record was removed
8465 * Fires when a Record has been updated
8466 * @param {Store} this
8467 * @param {Roo.data.Record} record The Record that was updated
8468 * @param {String} operation The update operation being performed. Value may be one of:
8470 Roo.data.Record.EDIT
8471 Roo.data.Record.REJECT
8472 Roo.data.Record.COMMIT
8478 * Fires when the data cache has been cleared.
8479 * @param {Store} this
8484 * Fires before a request is made for a new data object. If the beforeload handler returns false
8485 * the load action will be canceled.
8486 * @param {Store} this
8487 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8491 * @event beforeloadadd
8492 * Fires after a new set of Records has been loaded.
8493 * @param {Store} this
8494 * @param {Roo.data.Record[]} records The Records that were loaded
8495 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8497 beforeloadadd : true,
8500 * Fires after a new set of Records has been loaded, before they are added to the store.
8501 * @param {Store} this
8502 * @param {Roo.data.Record[]} records The Records that were loaded
8503 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8504 * @params {Object} return from reader
8508 * @event loadexception
8509 * Fires if an exception occurs in the Proxy during loading.
8510 * Called with the signature of the Proxy's "loadexception" event.
8511 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8514 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8515 * @param {Object} load options
8516 * @param {Object} jsonData from your request (normally this contains the Exception)
8518 loadexception : true
8522 this.proxy = Roo.factory(this.proxy, Roo.data);
8523 this.proxy.xmodule = this.xmodule || false;
8524 this.relayEvents(this.proxy, ["loadexception"]);
8526 this.sortToggle = {};
8527 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8529 Roo.data.Store.superclass.constructor.call(this);
8531 if(this.inlineData){
8532 this.loadData(this.inlineData);
8533 delete this.inlineData;
8537 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8539 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8540 * without a remote query - used by combo/forms at present.
8544 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8547 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8550 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8551 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8554 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8555 * on any HTTP request
8558 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8561 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8565 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8566 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8571 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8572 * loaded or when a record is removed. (defaults to false).
8574 pruneModifiedRecords : false,
8580 * Add Records to the Store and fires the add event.
8581 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8583 add : function(records){
8584 records = [].concat(records);
8585 for(var i = 0, len = records.length; i < len; i++){
8586 records[i].join(this);
8588 var index = this.data.length;
8589 this.data.addAll(records);
8590 this.fireEvent("add", this, records, index);
8594 * Remove a Record from the Store and fires the remove event.
8595 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8597 remove : function(record){
8598 var index = this.data.indexOf(record);
8599 this.data.removeAt(index);
8600 if(this.pruneModifiedRecords){
8601 this.modified.remove(record);
8603 this.fireEvent("remove", this, record, index);
8607 * Remove all Records from the Store and fires the clear event.
8609 removeAll : function(){
8611 if(this.pruneModifiedRecords){
8614 this.fireEvent("clear", this);
8618 * Inserts Records to the Store at the given index and fires the add event.
8619 * @param {Number} index The start index at which to insert the passed Records.
8620 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8622 insert : function(index, records){
8623 records = [].concat(records);
8624 for(var i = 0, len = records.length; i < len; i++){
8625 this.data.insert(index, records[i]);
8626 records[i].join(this);
8628 this.fireEvent("add", this, records, index);
8632 * Get the index within the cache of the passed Record.
8633 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8634 * @return {Number} The index of the passed Record. Returns -1 if not found.
8636 indexOf : function(record){
8637 return this.data.indexOf(record);
8641 * Get the index within the cache of the Record with the passed id.
8642 * @param {String} id The id of the Record to find.
8643 * @return {Number} The index of the Record. Returns -1 if not found.
8645 indexOfId : function(id){
8646 return this.data.indexOfKey(id);
8650 * Get the Record with the specified id.
8651 * @param {String} id The id of the Record to find.
8652 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8654 getById : function(id){
8655 return this.data.key(id);
8659 * Get the Record at the specified index.
8660 * @param {Number} index The index of the Record to find.
8661 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8663 getAt : function(index){
8664 return this.data.itemAt(index);
8668 * Returns a range of Records between specified indices.
8669 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8670 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8671 * @return {Roo.data.Record[]} An array of Records
8673 getRange : function(start, end){
8674 return this.data.getRange(start, end);
8678 storeOptions : function(o){
8679 o = Roo.apply({}, o);
8682 this.lastOptions = o;
8686 * Loads the Record cache from the configured Proxy using the configured Reader.
8688 * If using remote paging, then the first load call must specify the <em>start</em>
8689 * and <em>limit</em> properties in the options.params property to establish the initial
8690 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8692 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8693 * and this call will return before the new data has been loaded. Perform any post-processing
8694 * in a callback function, or in a "load" event handler.</strong>
8696 * @param {Object} options An object containing properties which control loading options:<ul>
8697 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8698 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8699 * passed the following arguments:<ul>
8700 * <li>r : Roo.data.Record[]</li>
8701 * <li>options: Options object from the load call</li>
8702 * <li>success: Boolean success indicator</li></ul></li>
8703 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8704 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8707 load : function(options){
8708 options = options || {};
8709 if(this.fireEvent("beforeload", this, options) !== false){
8710 this.storeOptions(options);
8711 var p = Roo.apply(options.params || {}, this.baseParams);
8712 // if meta was not loaded from remote source.. try requesting it.
8713 if (!this.reader.metaFromRemote) {
8716 if(this.sortInfo && this.remoteSort){
8717 var pn = this.paramNames;
8718 p[pn["sort"]] = this.sortInfo.field;
8719 p[pn["dir"]] = this.sortInfo.direction;
8721 if (this.multiSort) {
8722 var pn = this.paramNames;
8723 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8726 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8731 * Reloads the Record cache from the configured Proxy using the configured Reader and
8732 * the options from the last load operation performed.
8733 * @param {Object} options (optional) An object containing properties which may override the options
8734 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8735 * the most recently used options are reused).
8737 reload : function(options){
8738 this.load(Roo.applyIf(options||{}, this.lastOptions));
8742 // Called as a callback by the Reader during a load operation.
8743 loadRecords : function(o, options, success){
8744 if(!o || success === false){
8745 if(success !== false){
8746 this.fireEvent("load", this, [], options, o);
8748 if(options.callback){
8749 options.callback.call(options.scope || this, [], options, false);
8753 // if data returned failure - throw an exception.
8754 if (o.success === false) {
8755 // show a message if no listener is registered.
8756 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8757 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8759 // loadmask wil be hooked into this..
8760 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8763 var r = o.records, t = o.totalRecords || r.length;
8765 this.fireEvent("beforeloadadd", this, r, options, o);
8767 if(!options || options.add !== true){
8768 if(this.pruneModifiedRecords){
8771 for(var i = 0, len = r.length; i < len; i++){
8775 this.data = this.snapshot;
8776 delete this.snapshot;
8779 this.data.addAll(r);
8780 this.totalLength = t;
8782 this.fireEvent("datachanged", this);
8784 this.totalLength = Math.max(t, this.data.length+r.length);
8787 this.fireEvent("load", this, r, options, o);
8788 if(options.callback){
8789 options.callback.call(options.scope || this, r, options, true);
8795 * Loads data from a passed data block. A Reader which understands the format of the data
8796 * must have been configured in the constructor.
8797 * @param {Object} data The data block from which to read the Records. The format of the data expected
8798 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8799 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8801 loadData : function(o, append){
8802 var r = this.reader.readRecords(o);
8803 this.loadRecords(r, {add: append}, true);
8807 * Gets the number of cached records.
8809 * <em>If using paging, this may not be the total size of the dataset. If the data object
8810 * used by the Reader contains the dataset size, then the getTotalCount() function returns
8811 * the data set size</em>
8813 getCount : function(){
8814 return this.data.length || 0;
8818 * Gets the total number of records in the dataset as returned by the server.
8820 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8821 * the dataset size</em>
8823 getTotalCount : function(){
8824 return this.totalLength || 0;
8828 * Returns the sort state of the Store as an object with two properties:
8830 field {String} The name of the field by which the Records are sorted
8831 direction {String} The sort order, "ASC" or "DESC"
8834 getSortState : function(){
8835 return this.sortInfo;
8839 applySort : function(){
8840 if(this.sortInfo && !this.remoteSort){
8841 var s = this.sortInfo, f = s.field;
8842 var st = this.fields.get(f).sortType;
8843 var fn = function(r1, r2){
8844 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8845 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8847 this.data.sort(s.direction, fn);
8848 if(this.snapshot && this.snapshot != this.data){
8849 this.snapshot.sort(s.direction, fn);
8855 * Sets the default sort column and order to be used by the next load operation.
8856 * @param {String} fieldName The name of the field to sort by.
8857 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8859 setDefaultSort : function(field, dir){
8860 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
8865 * If remote sorting is used, the sort is performed on the server, and the cache is
8866 * reloaded. If local sorting is used, the cache is sorted internally.
8867 * @param {String} fieldName The name of the field to sort by.
8868 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8870 sort : function(fieldName, dir){
8871 var f = this.fields.get(fieldName);
8873 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
8875 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
8876 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
8881 this.sortToggle[f.name] = dir;
8882 this.sortInfo = {field: f.name, direction: dir};
8883 if(!this.remoteSort){
8885 this.fireEvent("datachanged", this);
8887 this.load(this.lastOptions);
8892 * Calls the specified function for each of the Records in the cache.
8893 * @param {Function} fn The function to call. The Record is passed as the first parameter.
8894 * Returning <em>false</em> aborts and exits the iteration.
8895 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
8897 each : function(fn, scope){
8898 this.data.each(fn, scope);
8902 * Gets all records modified since the last commit. Modified records are persisted across load operations
8903 * (e.g., during paging).
8904 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
8906 getModifiedRecords : function(){
8907 return this.modified;
8911 createFilterFn : function(property, value, anyMatch){
8912 if(!value.exec){ // not a regex
8913 value = String(value);
8914 if(value.length == 0){
8917 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
8920 return value.test(r.data[property]);
8925 * Sums the value of <i>property</i> for each record between start and end and returns the result.
8926 * @param {String} property A field on your records
8927 * @param {Number} start The record index to start at (defaults to 0)
8928 * @param {Number} end The last record index to include (defaults to length - 1)
8929 * @return {Number} The sum
8931 sum : function(property, start, end){
8932 var rs = this.data.items, v = 0;
8934 end = (end || end === 0) ? end : rs.length-1;
8936 for(var i = start; i <= end; i++){
8937 v += (rs[i].data[property] || 0);
8943 * Filter the records by a specified property.
8944 * @param {String} field A field on your records
8945 * @param {String/RegExp} value Either a string that the field
8946 * should start with or a RegExp to test against the field
8947 * @param {Boolean} anyMatch True to match any part not just the beginning
8949 filter : function(property, value, anyMatch){
8950 var fn = this.createFilterFn(property, value, anyMatch);
8951 return fn ? this.filterBy(fn) : this.clearFilter();
8955 * Filter by a function. The specified function will be called with each
8956 * record in this data source. If the function returns true the record is included,
8957 * otherwise it is filtered.
8958 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8959 * @param {Object} scope (optional) The scope of the function (defaults to this)
8961 filterBy : function(fn, scope){
8962 this.snapshot = this.snapshot || this.data;
8963 this.data = this.queryBy(fn, scope||this);
8964 this.fireEvent("datachanged", this);
8968 * Query the records by a specified property.
8969 * @param {String} field A field on your records
8970 * @param {String/RegExp} value Either a string that the field
8971 * should start with or a RegExp to test against the field
8972 * @param {Boolean} anyMatch True to match any part not just the beginning
8973 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8975 query : function(property, value, anyMatch){
8976 var fn = this.createFilterFn(property, value, anyMatch);
8977 return fn ? this.queryBy(fn) : this.data.clone();
8981 * Query by a function. The specified function will be called with each
8982 * record in this data source. If the function returns true the record is included
8984 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8985 * @param {Object} scope (optional) The scope of the function (defaults to this)
8986 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8988 queryBy : function(fn, scope){
8989 var data = this.snapshot || this.data;
8990 return data.filterBy(fn, scope||this);
8994 * Collects unique values for a particular dataIndex from this store.
8995 * @param {String} dataIndex The property to collect
8996 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
8997 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
8998 * @return {Array} An array of the unique values
9000 collect : function(dataIndex, allowNull, bypassFilter){
9001 var d = (bypassFilter === true && this.snapshot) ?
9002 this.snapshot.items : this.data.items;
9003 var v, sv, r = [], l = {};
9004 for(var i = 0, len = d.length; i < len; i++){
9005 v = d[i].data[dataIndex];
9007 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9016 * Revert to a view of the Record cache with no filtering applied.
9017 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9019 clearFilter : function(suppressEvent){
9020 if(this.snapshot && this.snapshot != this.data){
9021 this.data = this.snapshot;
9022 delete this.snapshot;
9023 if(suppressEvent !== true){
9024 this.fireEvent("datachanged", this);
9030 afterEdit : function(record){
9031 if(this.modified.indexOf(record) == -1){
9032 this.modified.push(record);
9034 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9038 afterReject : function(record){
9039 this.modified.remove(record);
9040 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9044 afterCommit : function(record){
9045 this.modified.remove(record);
9046 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9050 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9051 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9053 commitChanges : function(){
9054 var m = this.modified.slice(0);
9056 for(var i = 0, len = m.length; i < len; i++){
9062 * Cancel outstanding changes on all changed records.
9064 rejectChanges : function(){
9065 var m = this.modified.slice(0);
9067 for(var i = 0, len = m.length; i < len; i++){
9072 onMetaChange : function(meta, rtype, o){
9073 this.recordType = rtype;
9074 this.fields = rtype.prototype.fields;
9075 delete this.snapshot;
9076 this.sortInfo = meta.sortInfo || this.sortInfo;
9078 this.fireEvent('metachange', this, this.reader.meta);
9081 moveIndex : function(data, type)
9083 var index = this.indexOf(data);
9085 var newIndex = index + type;
9089 this.insert(newIndex, data);
9094 * Ext JS Library 1.1.1
9095 * Copyright(c) 2006-2007, Ext JS, LLC.
9097 * Originally Released Under LGPL - original licence link has changed is not relivant.
9100 * <script type="text/javascript">
9104 * @class Roo.data.SimpleStore
9105 * @extends Roo.data.Store
9106 * Small helper class to make creating Stores from Array data easier.
9107 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9108 * @cfg {Array} fields An array of field definition objects, or field name strings.
9109 * @cfg {Array} data The multi-dimensional array of data
9111 * @param {Object} config
9113 Roo.data.SimpleStore = function(config){
9114 Roo.data.SimpleStore.superclass.constructor.call(this, {
9116 reader: new Roo.data.ArrayReader({
9119 Roo.data.Record.create(config.fields)
9121 proxy : new Roo.data.MemoryProxy(config.data)
9125 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9127 * Ext JS Library 1.1.1
9128 * Copyright(c) 2006-2007, Ext JS, LLC.
9130 * Originally Released Under LGPL - original licence link has changed is not relivant.
9133 * <script type="text/javascript">
9138 * @extends Roo.data.Store
9139 * @class Roo.data.JsonStore
9140 * Small helper class to make creating Stores for JSON data easier. <br/>
9142 var store = new Roo.data.JsonStore({
9143 url: 'get-images.php',
9145 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9148 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9149 * JsonReader and HttpProxy (unless inline data is provided).</b>
9150 * @cfg {Array} fields An array of field definition objects, or field name strings.
9152 * @param {Object} config
9154 Roo.data.JsonStore = function(c){
9155 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9156 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9157 reader: new Roo.data.JsonReader(c, c.fields)
9160 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9162 * Ext JS Library 1.1.1
9163 * Copyright(c) 2006-2007, Ext JS, LLC.
9165 * Originally Released Under LGPL - original licence link has changed is not relivant.
9168 * <script type="text/javascript">
9172 Roo.data.Field = function(config){
9173 if(typeof config == "string"){
9174 config = {name: config};
9176 Roo.apply(this, config);
9182 var st = Roo.data.SortTypes;
9183 // named sortTypes are supported, here we look them up
9184 if(typeof this.sortType == "string"){
9185 this.sortType = st[this.sortType];
9188 // set default sortType for strings and dates
9192 this.sortType = st.asUCString;
9195 this.sortType = st.asDate;
9198 this.sortType = st.none;
9203 var stripRe = /[\$,%]/g;
9205 // prebuilt conversion function for this field, instead of
9206 // switching every time we're reading a value
9208 var cv, dateFormat = this.dateFormat;
9213 cv = function(v){ return v; };
9216 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9220 return v !== undefined && v !== null && v !== '' ?
9221 parseInt(String(v).replace(stripRe, ""), 10) : '';
9226 return v !== undefined && v !== null && v !== '' ?
9227 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9232 cv = function(v){ return v === true || v === "true" || v == 1; };
9239 if(v instanceof Date){
9243 if(dateFormat == "timestamp"){
9244 return new Date(v*1000);
9246 return Date.parseDate(v, dateFormat);
9248 var parsed = Date.parse(v);
9249 return parsed ? new Date(parsed) : null;
9258 Roo.data.Field.prototype = {
9266 * Ext JS Library 1.1.1
9267 * Copyright(c) 2006-2007, Ext JS, LLC.
9269 * Originally Released Under LGPL - original licence link has changed is not relivant.
9272 * <script type="text/javascript">
9275 // Base class for reading structured data from a data source. This class is intended to be
9276 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9279 * @class Roo.data.DataReader
9280 * Base class for reading structured data from a data source. This class is intended to be
9281 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9284 Roo.data.DataReader = function(meta, recordType){
9288 this.recordType = recordType instanceof Array ?
9289 Roo.data.Record.create(recordType) : recordType;
9292 Roo.data.DataReader.prototype = {
9294 * Create an empty record
9295 * @param {Object} data (optional) - overlay some values
9296 * @return {Roo.data.Record} record created.
9298 newRow : function(d) {
9300 this.recordType.prototype.fields.each(function(c) {
9302 case 'int' : da[c.name] = 0; break;
9303 case 'date' : da[c.name] = new Date(); break;
9304 case 'float' : da[c.name] = 0.0; break;
9305 case 'boolean' : da[c.name] = false; break;
9306 default : da[c.name] = ""; break;
9310 return new this.recordType(Roo.apply(da, d));
9315 * Ext JS Library 1.1.1
9316 * Copyright(c) 2006-2007, Ext JS, LLC.
9318 * Originally Released Under LGPL - original licence link has changed is not relivant.
9321 * <script type="text/javascript">
9325 * @class Roo.data.DataProxy
9326 * @extends Roo.data.Observable
9327 * This class is an abstract base class for implementations which provide retrieval of
9328 * unformatted data objects.<br>
9330 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9331 * (of the appropriate type which knows how to parse the data object) to provide a block of
9332 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9334 * Custom implementations must implement the load method as described in
9335 * {@link Roo.data.HttpProxy#load}.
9337 Roo.data.DataProxy = function(){
9341 * Fires before a network request is made to retrieve a data object.
9342 * @param {Object} This DataProxy object.
9343 * @param {Object} params The params parameter to the load function.
9348 * Fires before the load method's callback is called.
9349 * @param {Object} This DataProxy object.
9350 * @param {Object} o The data object.
9351 * @param {Object} arg The callback argument object passed to the load function.
9355 * @event loadexception
9356 * Fires if an Exception occurs during data retrieval.
9357 * @param {Object} This DataProxy object.
9358 * @param {Object} o The data object.
9359 * @param {Object} arg The callback argument object passed to the load function.
9360 * @param {Object} e The Exception.
9362 loadexception : true
9364 Roo.data.DataProxy.superclass.constructor.call(this);
9367 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9370 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9374 * Ext JS Library 1.1.1
9375 * Copyright(c) 2006-2007, Ext JS, LLC.
9377 * Originally Released Under LGPL - original licence link has changed is not relivant.
9380 * <script type="text/javascript">
9383 * @class Roo.data.MemoryProxy
9384 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9385 * to the Reader when its load method is called.
9387 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9389 Roo.data.MemoryProxy = function(data){
9393 Roo.data.MemoryProxy.superclass.constructor.call(this);
9397 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9399 * Load data from the requested source (in this case an in-memory
9400 * data object passed to the constructor), read the data object into
9401 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9402 * process that block using the passed callback.
9403 * @param {Object} params This parameter is not used by the MemoryProxy class.
9404 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9405 * object into a block of Roo.data.Records.
9406 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9407 * The function must be passed <ul>
9408 * <li>The Record block object</li>
9409 * <li>The "arg" argument from the load function</li>
9410 * <li>A boolean success indicator</li>
9412 * @param {Object} scope The scope in which to call the callback
9413 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9415 load : function(params, reader, callback, scope, arg){
9416 params = params || {};
9419 result = reader.readRecords(this.data);
9421 this.fireEvent("loadexception", this, arg, null, e);
9422 callback.call(scope, null, arg, false);
9425 callback.call(scope, result, arg, true);
9429 update : function(params, records){
9434 * Ext JS Library 1.1.1
9435 * Copyright(c) 2006-2007, Ext JS, LLC.
9437 * Originally Released Under LGPL - original licence link has changed is not relivant.
9440 * <script type="text/javascript">
9443 * @class Roo.data.HttpProxy
9444 * @extends Roo.data.DataProxy
9445 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9446 * configured to reference a certain URL.<br><br>
9448 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9449 * from which the running page was served.<br><br>
9451 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9453 * Be aware that to enable the browser to parse an XML document, the server must set
9454 * the Content-Type header in the HTTP response to "text/xml".
9456 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9457 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9458 * will be used to make the request.
9460 Roo.data.HttpProxy = function(conn){
9461 Roo.data.HttpProxy.superclass.constructor.call(this);
9462 // is conn a conn config or a real conn?
9464 this.useAjax = !conn || !conn.events;
9468 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9469 // thse are take from connection...
9472 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9475 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9476 * extra parameters to each request made by this object. (defaults to undefined)
9479 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9480 * to each request made by this object. (defaults to undefined)
9483 * @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)
9486 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9489 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9495 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9499 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9500 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9501 * a finer-grained basis than the DataProxy events.
9503 getConnection : function(){
9504 return this.useAjax ? Roo.Ajax : this.conn;
9508 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9509 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9510 * process that block using the passed callback.
9511 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9512 * for the request to the remote server.
9513 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9514 * object into a block of Roo.data.Records.
9515 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9516 * The function must be passed <ul>
9517 * <li>The Record block object</li>
9518 * <li>The "arg" argument from the load function</li>
9519 * <li>A boolean success indicator</li>
9521 * @param {Object} scope The scope in which to call the callback
9522 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9524 load : function(params, reader, callback, scope, arg){
9525 if(this.fireEvent("beforeload", this, params) !== false){
9527 params : params || {},
9529 callback : callback,
9534 callback : this.loadResponse,
9538 Roo.applyIf(o, this.conn);
9539 if(this.activeRequest){
9540 Roo.Ajax.abort(this.activeRequest);
9542 this.activeRequest = Roo.Ajax.request(o);
9544 this.conn.request(o);
9547 callback.call(scope||this, null, arg, false);
9552 loadResponse : function(o, success, response){
9553 delete this.activeRequest;
9555 this.fireEvent("loadexception", this, o, response);
9556 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9561 result = o.reader.read(response);
9563 this.fireEvent("loadexception", this, o, response, e);
9564 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9568 this.fireEvent("load", this, o, o.request.arg);
9569 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9573 update : function(dataSet){
9578 updateResponse : function(dataSet){
9583 * Ext JS Library 1.1.1
9584 * Copyright(c) 2006-2007, Ext JS, LLC.
9586 * Originally Released Under LGPL - original licence link has changed is not relivant.
9589 * <script type="text/javascript">
9593 * @class Roo.data.ScriptTagProxy
9594 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9595 * other than the originating domain of the running page.<br><br>
9597 * <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
9598 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9600 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9601 * source code that is used as the source inside a <script> tag.<br><br>
9603 * In order for the browser to process the returned data, the server must wrap the data object
9604 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9605 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9606 * depending on whether the callback name was passed:
9609 boolean scriptTag = false;
9610 String cb = request.getParameter("callback");
9613 response.setContentType("text/javascript");
9615 response.setContentType("application/x-json");
9617 Writer out = response.getWriter();
9619 out.write(cb + "(");
9621 out.print(dataBlock.toJsonString());
9628 * @param {Object} config A configuration object.
9630 Roo.data.ScriptTagProxy = function(config){
9631 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9632 Roo.apply(this, config);
9633 this.head = document.getElementsByTagName("head")[0];
9636 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9638 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9640 * @cfg {String} url The URL from which to request the data object.
9643 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9647 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9648 * the server the name of the callback function set up by the load call to process the returned data object.
9649 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9650 * javascript output which calls this named function passing the data object as its only parameter.
9652 callbackParam : "callback",
9654 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9655 * name to the request.
9660 * Load data from the configured URL, read the data object into
9661 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9662 * process that block using the passed callback.
9663 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9664 * for the request to the remote server.
9665 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9666 * object into a block of Roo.data.Records.
9667 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9668 * The function must be passed <ul>
9669 * <li>The Record block object</li>
9670 * <li>The "arg" argument from the load function</li>
9671 * <li>A boolean success indicator</li>
9673 * @param {Object} scope The scope in which to call the callback
9674 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9676 load : function(params, reader, callback, scope, arg){
9677 if(this.fireEvent("beforeload", this, params) !== false){
9679 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9682 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9684 url += "&_dc=" + (new Date().getTime());
9686 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9689 cb : "stcCallback"+transId,
9690 scriptId : "stcScript"+transId,
9694 callback : callback,
9700 window[trans.cb] = function(o){
9701 conn.handleResponse(o, trans);
9704 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9706 if(this.autoAbort !== false){
9710 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9712 var script = document.createElement("script");
9713 script.setAttribute("src", url);
9714 script.setAttribute("type", "text/javascript");
9715 script.setAttribute("id", trans.scriptId);
9716 this.head.appendChild(script);
9720 callback.call(scope||this, null, arg, false);
9725 isLoading : function(){
9726 return this.trans ? true : false;
9730 * Abort the current server request.
9733 if(this.isLoading()){
9734 this.destroyTrans(this.trans);
9739 destroyTrans : function(trans, isLoaded){
9740 this.head.removeChild(document.getElementById(trans.scriptId));
9741 clearTimeout(trans.timeoutId);
9743 window[trans.cb] = undefined;
9745 delete window[trans.cb];
9748 // if hasn't been loaded, wait for load to remove it to prevent script error
9749 window[trans.cb] = function(){
9750 window[trans.cb] = undefined;
9752 delete window[trans.cb];
9759 handleResponse : function(o, trans){
9761 this.destroyTrans(trans, true);
9764 result = trans.reader.readRecords(o);
9766 this.fireEvent("loadexception", this, o, trans.arg, e);
9767 trans.callback.call(trans.scope||window, null, trans.arg, false);
9770 this.fireEvent("load", this, o, trans.arg);
9771 trans.callback.call(trans.scope||window, result, trans.arg, true);
9775 handleFailure : function(trans){
9777 this.destroyTrans(trans, false);
9778 this.fireEvent("loadexception", this, null, trans.arg);
9779 trans.callback.call(trans.scope||window, null, trans.arg, false);
9783 * Ext JS Library 1.1.1
9784 * Copyright(c) 2006-2007, Ext JS, LLC.
9786 * Originally Released Under LGPL - original licence link has changed is not relivant.
9789 * <script type="text/javascript">
9793 * @class Roo.data.JsonReader
9794 * @extends Roo.data.DataReader
9795 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9796 * based on mappings in a provided Roo.data.Record constructor.
9798 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9799 * in the reply previously.
9804 var RecordDef = Roo.data.Record.create([
9805 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
9806 {name: 'occupation'} // This field will use "occupation" as the mapping.
9808 var myReader = new Roo.data.JsonReader({
9809 totalProperty: "results", // The property which contains the total dataset size (optional)
9810 root: "rows", // The property which contains an Array of row objects
9811 id: "id" // The property within each row object that provides an ID for the record (optional)
9815 * This would consume a JSON file like this:
9817 { 'results': 2, 'rows': [
9818 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9819 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9822 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9823 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9824 * paged from the remote server.
9825 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9826 * @cfg {String} root name of the property which contains the Array of row objects.
9827 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9829 * Create a new JsonReader
9830 * @param {Object} meta Metadata configuration options
9831 * @param {Object} recordType Either an Array of field definition objects,
9832 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9834 Roo.data.JsonReader = function(meta, recordType){
9837 // set some defaults:
9839 totalProperty: 'total',
9840 successProperty : 'success',
9845 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9847 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9850 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
9851 * Used by Store query builder to append _requestMeta to params.
9854 metaFromRemote : false,
9856 * This method is only used by a DataProxy which has retrieved data from a remote server.
9857 * @param {Object} response The XHR object which contains the JSON data in its responseText.
9858 * @return {Object} data A data block which is used by an Roo.data.Store object as
9859 * a cache of Roo.data.Records.
9861 read : function(response){
9862 var json = response.responseText;
9864 var o = /* eval:var:o */ eval("("+json+")");
9866 throw {message: "JsonReader.read: Json object not found"};
9872 this.metaFromRemote = true;
9873 this.meta = o.metaData;
9874 this.recordType = Roo.data.Record.create(o.metaData.fields);
9875 this.onMetaChange(this.meta, this.recordType, o);
9877 return this.readRecords(o);
9880 // private function a store will implement
9881 onMetaChange : function(meta, recordType, o){
9888 simpleAccess: function(obj, subsc) {
9895 getJsonAccessor: function(){
9897 return function(expr) {
9899 return(re.test(expr))
9900 ? new Function("obj", "return obj." + expr)
9910 * Create a data block containing Roo.data.Records from an XML document.
9911 * @param {Object} o An object which contains an Array of row objects in the property specified
9912 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
9913 * which contains the total size of the dataset.
9914 * @return {Object} data A data block which is used by an Roo.data.Store object as
9915 * a cache of Roo.data.Records.
9917 readRecords : function(o){
9919 * After any data loads, the raw JSON data is available for further custom processing.
9923 var s = this.meta, Record = this.recordType,
9924 f = Record.prototype.fields, fi = f.items, fl = f.length;
9926 // Generate extraction functions for the totalProperty, the root, the id, and for each field
9928 if(s.totalProperty) {
9929 this.getTotal = this.getJsonAccessor(s.totalProperty);
9931 if(s.successProperty) {
9932 this.getSuccess = this.getJsonAccessor(s.successProperty);
9934 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
9936 var g = this.getJsonAccessor(s.id);
9937 this.getId = function(rec) {
9939 return (r === undefined || r === "") ? null : r;
9942 this.getId = function(){return null;};
9945 for(var jj = 0; jj < fl; jj++){
9947 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
9948 this.ef[jj] = this.getJsonAccessor(map);
9952 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
9953 if(s.totalProperty){
9954 var vt = parseInt(this.getTotal(o), 10);
9959 if(s.successProperty){
9960 var vs = this.getSuccess(o);
9961 if(vs === false || vs === 'false'){
9966 for(var i = 0; i < c; i++){
9969 var id = this.getId(n);
9970 for(var j = 0; j < fl; j++){
9972 var v = this.ef[j](n);
9974 Roo.log('missing convert for ' + f.name);
9978 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
9980 var record = new Record(values, id);
9982 records[i] = record;
9988 totalRecords : totalRecords
9993 * Ext JS Library 1.1.1
9994 * Copyright(c) 2006-2007, Ext JS, LLC.
9996 * Originally Released Under LGPL - original licence link has changed is not relivant.
9999 * <script type="text/javascript">
10003 * @class Roo.data.ArrayReader
10004 * @extends Roo.data.DataReader
10005 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10006 * Each element of that Array represents a row of data fields. The
10007 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10008 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10012 var RecordDef = Roo.data.Record.create([
10013 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10014 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10016 var myReader = new Roo.data.ArrayReader({
10017 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10021 * This would consume an Array like this:
10023 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10025 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10027 * Create a new JsonReader
10028 * @param {Object} meta Metadata configuration options.
10029 * @param {Object} recordType Either an Array of field definition objects
10030 * as specified to {@link Roo.data.Record#create},
10031 * or an {@link Roo.data.Record} object
10032 * created using {@link Roo.data.Record#create}.
10034 Roo.data.ArrayReader = function(meta, recordType){
10035 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10038 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10040 * Create a data block containing Roo.data.Records from an XML document.
10041 * @param {Object} o An Array of row objects which represents the dataset.
10042 * @return {Object} data A data block which is used by an Roo.data.Store object as
10043 * a cache of Roo.data.Records.
10045 readRecords : function(o){
10046 var sid = this.meta ? this.meta.id : null;
10047 var recordType = this.recordType, fields = recordType.prototype.fields;
10050 for(var i = 0; i < root.length; i++){
10053 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10054 for(var j = 0, jlen = fields.length; j < jlen; j++){
10055 var f = fields.items[j];
10056 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10057 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10059 values[f.name] = v;
10061 var record = new recordType(values, id);
10063 records[records.length] = record;
10067 totalRecords : records.length
10076 * @class Roo.bootstrap.ComboBox
10077 * @extends Roo.bootstrap.TriggerField
10078 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10079 * @cfg {Boolean} append (true|false) default false
10080 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10081 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10082 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10083 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10085 * Create a new ComboBox.
10086 * @param {Object} config Configuration options
10088 Roo.bootstrap.ComboBox = function(config){
10089 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10093 * Fires when the dropdown list is expanded
10094 * @param {Roo.bootstrap.ComboBox} combo This combo box
10099 * Fires when the dropdown list is collapsed
10100 * @param {Roo.bootstrap.ComboBox} combo This combo box
10104 * @event beforeselect
10105 * Fires before a list item is selected. Return false to cancel the selection.
10106 * @param {Roo.bootstrap.ComboBox} combo This combo box
10107 * @param {Roo.data.Record} record The data record returned from the underlying store
10108 * @param {Number} index The index of the selected item in the dropdown list
10110 'beforeselect' : true,
10113 * Fires when a list item is selected
10114 * @param {Roo.bootstrap.ComboBox} combo This combo box
10115 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10116 * @param {Number} index The index of the selected item in the dropdown list
10120 * @event beforequery
10121 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10122 * The event object passed has these properties:
10123 * @param {Roo.bootstrap.ComboBox} combo This combo box
10124 * @param {String} query The query
10125 * @param {Boolean} forceAll true to force "all" query
10126 * @param {Boolean} cancel true to cancel the query
10127 * @param {Object} e The query event object
10129 'beforequery': true,
10132 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10133 * @param {Roo.bootstrap.ComboBox} combo This combo box
10138 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10139 * @param {Roo.bootstrap.ComboBox} combo This combo box
10140 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10145 * Fires when the remove value from the combobox array
10146 * @param {Roo.bootstrap.ComboBox} combo This combo box
10153 this.tickItems = [];
10155 this.selectedIndex = -1;
10156 if(this.mode == 'local'){
10157 if(config.queryDelay === undefined){
10158 this.queryDelay = 10;
10160 if(config.minChars === undefined){
10166 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10169 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10170 * rendering into an Roo.Editor, defaults to false)
10173 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10174 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10177 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10180 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10181 * the dropdown list (defaults to undefined, with no header element)
10185 * @cfg {String/Roo.Template} tpl The template to use to render the output
10189 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10191 listWidth: undefined,
10193 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10194 * mode = 'remote' or 'text' if mode = 'local')
10196 displayField: undefined,
10198 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10199 * mode = 'remote' or 'value' if mode = 'local').
10200 * Note: use of a valueField requires the user make a selection
10201 * in order for a value to be mapped.
10203 valueField: undefined,
10207 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10208 * field's data value (defaults to the underlying DOM element's name)
10210 hiddenName: undefined,
10212 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10216 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10218 selectedClass: 'active',
10221 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10225 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10226 * anchor positions (defaults to 'tl-bl')
10228 listAlign: 'tl-bl?',
10230 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10234 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10235 * query specified by the allQuery config option (defaults to 'query')
10237 triggerAction: 'query',
10239 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10240 * (defaults to 4, does not apply if editable = false)
10244 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10245 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10249 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10250 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10254 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10255 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10259 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10260 * when editable = true (defaults to false)
10262 selectOnFocus:false,
10264 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10266 queryParam: 'query',
10268 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10269 * when mode = 'remote' (defaults to 'Loading...')
10271 loadingText: 'Loading...',
10273 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10277 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10281 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10282 * traditional select (defaults to true)
10286 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10290 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10294 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10295 * listWidth has a higher value)
10299 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10300 * allow the user to set arbitrary text into the field (defaults to false)
10302 forceSelection:false,
10304 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10305 * if typeAhead = true (defaults to 250)
10307 typeAheadDelay : 250,
10309 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10310 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10312 valueNotFoundText : undefined,
10314 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10316 blockFocus : false,
10319 * @cfg {Boolean} disableClear Disable showing of clear button.
10321 disableClear : false,
10323 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10325 alwaysQuery : false,
10328 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10342 btnPosition : 'right',
10343 triggerList : true,
10344 // element that contains real text value.. (when hidden is used..)
10346 getAutoCreate : function()
10353 if(!this.tickable){
10354 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10359 * ComboBox with tickable selections
10362 var align = this.labelAlign || this.parentLabelAlign();
10365 cls : 'form-group roo-combobox-tickable' //input-group
10371 cls : 'tickable-buttons',
10376 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10383 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10390 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10397 Roo.each(buttons.cn, function(c){
10399 c.cls += ' btn-' + _this.size;
10402 if (_this.disabled) {
10413 cls: 'form-hidden-field'
10417 cls: 'select2-choices',
10421 cls: 'select2-search-field',
10433 cls: 'select2-container input-group select2-container-multi',
10438 // cls: 'typeahead typeahead-long dropdown-menu',
10439 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
10444 if (align ==='left' && this.fieldLabel.length) {
10446 Roo.log("left and has label");
10452 cls : 'control-label col-sm-' + this.labelWidth,
10453 html : this.fieldLabel
10457 cls : "col-sm-" + (12 - this.labelWidth),
10464 } else if ( this.fieldLabel.length) {
10470 //cls : 'input-group-addon',
10471 html : this.fieldLabel
10481 Roo.log(" no label && no align");
10488 ['xs','sm','md','lg'].map(function(size){
10489 if (settings[size]) {
10490 cfg.cls += ' col-' + size + '-' + settings[size];
10499 initEvents: function()
10503 throw "can not find store for combo";
10505 this.store = Roo.factory(this.store, Roo.data);
10508 this.initTickableEvnets();
10512 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10514 if(this.hiddenName){
10516 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10518 this.hiddenField.dom.value =
10519 this.hiddenValue !== undefined ? this.hiddenValue :
10520 this.value !== undefined ? this.value : '';
10522 // prevent input submission
10523 this.el.dom.removeAttribute('name');
10524 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10529 // this.el.dom.setAttribute('autocomplete', 'off');
10532 var cls = 'x-combo-list';
10534 //this.list = new Roo.Layer({
10535 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10541 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10542 _this.list.setWidth(lw);
10545 this.list.on('mouseover', this.onViewOver, this);
10546 this.list.on('mousemove', this.onViewMove, this);
10548 this.list.on('scroll', this.onViewScroll, this);
10551 this.list.swallowEvent('mousewheel');
10552 this.assetHeight = 0;
10555 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10556 this.assetHeight += this.header.getHeight();
10559 this.innerList = this.list.createChild({cls:cls+'-inner'});
10560 this.innerList.on('mouseover', this.onViewOver, this);
10561 this.innerList.on('mousemove', this.onViewMove, this);
10562 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10564 if(this.allowBlank && !this.pageSize && !this.disableClear){
10565 this.footer = this.list.createChild({cls:cls+'-ft'});
10566 this.pageTb = new Roo.Toolbar(this.footer);
10570 this.footer = this.list.createChild({cls:cls+'-ft'});
10571 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10572 {pageSize: this.pageSize});
10576 if (this.pageTb && this.allowBlank && !this.disableClear) {
10578 this.pageTb.add(new Roo.Toolbar.Fill(), {
10579 cls: 'x-btn-icon x-btn-clear',
10581 handler: function()
10584 _this.clearValue();
10585 _this.onSelect(false, -1);
10590 this.assetHeight += this.footer.getHeight();
10595 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10598 this.view = new Roo.View(this.list, this.tpl, {
10599 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10601 //this.view.wrapEl.setDisplayed(false);
10602 this.view.on('click', this.onViewClick, this);
10606 this.store.on('beforeload', this.onBeforeLoad, this);
10607 this.store.on('load', this.onLoad, this);
10608 this.store.on('loadexception', this.onLoadException, this);
10610 if(this.resizable){
10611 this.resizer = new Roo.Resizable(this.list, {
10612 pinned:true, handles:'se'
10614 this.resizer.on('resize', function(r, w, h){
10615 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10616 this.listWidth = w;
10617 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10618 this.restrictHeight();
10620 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10623 if(!this.editable){
10624 this.editable = true;
10625 this.setEditable(false);
10630 if (typeof(this.events.add.listeners) != 'undefined') {
10632 this.addicon = this.wrap.createChild(
10633 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10635 this.addicon.on('click', function(e) {
10636 this.fireEvent('add', this);
10639 if (typeof(this.events.edit.listeners) != 'undefined') {
10641 this.editicon = this.wrap.createChild(
10642 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10643 if (this.addicon) {
10644 this.editicon.setStyle('margin-left', '40px');
10646 this.editicon.on('click', function(e) {
10648 // we fire even if inothing is selected..
10649 this.fireEvent('edit', this, this.lastData );
10655 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10656 "up" : function(e){
10657 this.inKeyMode = true;
10661 "down" : function(e){
10662 if(!this.isExpanded()){
10663 this.onTriggerClick();
10665 this.inKeyMode = true;
10670 "enter" : function(e){
10671 // this.onViewClick();
10675 if(this.fireEvent("specialkey", this, e)){
10676 this.onViewClick(false);
10682 "esc" : function(e){
10686 "tab" : function(e){
10689 if(this.fireEvent("specialkey", this, e)){
10690 this.onViewClick(false);
10698 doRelay : function(foo, bar, hname){
10699 if(hname == 'down' || this.scope.isExpanded()){
10700 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10709 this.queryDelay = Math.max(this.queryDelay || 10,
10710 this.mode == 'local' ? 10 : 250);
10713 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10715 if(this.typeAhead){
10716 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10718 if(this.editable !== false){
10719 this.inputEl().on("keyup", this.onKeyUp, this);
10721 if(this.forceSelection){
10722 this.inputEl().on('blur', this.doForce, this);
10726 this.choices = this.el.select('ul.select2-choices', true).first();
10727 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10731 initTickableEvnets: function()
10735 if(this.hiddenName){
10737 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10739 this.hiddenField.dom.value =
10740 this.hiddenValue !== undefined ? this.hiddenValue :
10741 this.value !== undefined ? this.value : '';
10743 // prevent input submission
10744 this.el.dom.removeAttribute('name');
10745 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10750 // this.list = this.el.select('ul.dropdown-menu',true).first();
10752 this.choices = this.el.select('ul.select2-choices', true).first();
10753 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10754 if(this.triggerList){
10755 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
10758 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10759 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
10761 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10762 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10764 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10765 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10767 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10768 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10769 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10772 this.cancelBtn.hide();
10777 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10778 _this.list.setWidth(lw);
10781 this.list.on('mouseover', this.onViewOver, this);
10782 this.list.on('mousemove', this.onViewMove, this);
10784 this.list.on('scroll', this.onViewScroll, this);
10787 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>';
10790 this.view = new Roo.View(this.list, this.tpl, {
10791 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10794 //this.view.wrapEl.setDisplayed(false);
10795 this.view.on('click', this.onViewClick, this);
10799 this.store.on('beforeload', this.onBeforeLoad, this);
10800 this.store.on('load', this.onLoad, this);
10801 this.store.on('loadexception', this.onLoadException, this);
10803 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
10804 // "up" : function(e){
10805 // this.inKeyMode = true;
10806 // this.selectPrev();
10809 // "down" : function(e){
10810 // if(!this.isExpanded()){
10811 // this.onTriggerClick();
10813 // this.inKeyMode = true;
10814 // this.selectNext();
10818 // "enter" : function(e){
10819 //// this.onViewClick();
10821 // this.collapse();
10823 // if(this.fireEvent("specialkey", this, e)){
10824 // this.onViewClick(false);
10830 // "esc" : function(e){
10831 // this.collapse();
10834 // "tab" : function(e){
10835 // this.collapse();
10837 // if(this.fireEvent("specialkey", this, e)){
10838 // this.onViewClick(false);
10846 // doRelay : function(foo, bar, hname){
10847 // if(hname == 'down' || this.scope.isExpanded()){
10848 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10853 // forceKeyDown: true
10857 this.queryDelay = Math.max(this.queryDelay || 10,
10858 this.mode == 'local' ? 10 : 250);
10861 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10863 if(this.typeAhead){
10864 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10868 onDestroy : function(){
10870 this.view.setStore(null);
10871 this.view.el.removeAllListeners();
10872 this.view.el.remove();
10873 this.view.purgeListeners();
10876 this.list.dom.innerHTML = '';
10880 this.store.un('beforeload', this.onBeforeLoad, this);
10881 this.store.un('load', this.onLoad, this);
10882 this.store.un('loadexception', this.onLoadException, this);
10884 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
10888 fireKey : function(e){
10889 if(e.isNavKeyPress() && !this.list.isVisible()){
10890 this.fireEvent("specialkey", this, e);
10895 onResize: function(w, h){
10896 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
10898 // if(typeof w != 'number'){
10899 // // we do not handle it!?!?
10902 // var tw = this.trigger.getWidth();
10903 // // tw += this.addicon ? this.addicon.getWidth() : 0;
10904 // // tw += this.editicon ? this.editicon.getWidth() : 0;
10906 // this.inputEl().setWidth( this.adjustWidth('input', x));
10908 // //this.trigger.setStyle('left', x+'px');
10910 // if(this.list && this.listWidth === undefined){
10911 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
10912 // this.list.setWidth(lw);
10913 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10921 * Allow or prevent the user from directly editing the field text. If false is passed,
10922 * the user will only be able to select from the items defined in the dropdown list. This method
10923 * is the runtime equivalent of setting the 'editable' config option at config time.
10924 * @param {Boolean} value True to allow the user to directly edit the field text
10926 setEditable : function(value){
10927 if(value == this.editable){
10930 this.editable = value;
10932 this.inputEl().dom.setAttribute('readOnly', true);
10933 this.inputEl().on('mousedown', this.onTriggerClick, this);
10934 this.inputEl().addClass('x-combo-noedit');
10936 this.inputEl().dom.setAttribute('readOnly', false);
10937 this.inputEl().un('mousedown', this.onTriggerClick, this);
10938 this.inputEl().removeClass('x-combo-noedit');
10944 onBeforeLoad : function(combo,opts){
10945 if(!this.hasFocus){
10949 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
10951 // this.restrictHeight();
10952 this.selectedIndex = -1;
10956 onLoad : function(){
10958 this.hasQuery = false;
10960 if(!this.hasFocus){
10964 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10965 this.loading.hide();
10968 if(this.store.getCount() > 0){
10970 // this.restrictHeight();
10971 if(this.lastQuery == this.allQuery){
10972 if(this.editable && !this.tickable){
10973 this.inputEl().dom.select();
10975 if(!this.selectByValue(this.value, true) && this.autoFocus){
10976 this.select(0, true);
10979 if(this.autoFocus){
10982 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
10983 this.taTask.delay(this.typeAheadDelay);
10987 this.onEmptyResults();
10993 onLoadException : function()
10995 this.hasQuery = false;
10997 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10998 this.loading.hide();
11002 Roo.log(this.store.reader.jsonData);
11003 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11005 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11011 onTypeAhead : function(){
11012 if(this.store.getCount() > 0){
11013 var r = this.store.getAt(0);
11014 var newValue = r.data[this.displayField];
11015 var len = newValue.length;
11016 var selStart = this.getRawValue().length;
11018 if(selStart != len){
11019 this.setRawValue(newValue);
11020 this.selectText(selStart, newValue.length);
11026 onSelect : function(record, index){
11028 if(this.fireEvent('beforeselect', this, record, index) !== false){
11030 this.setFromData(index > -1 ? record.data : false);
11033 this.fireEvent('select', this, record, index);
11038 * Returns the currently selected field value or empty string if no value is set.
11039 * @return {String} value The selected value
11041 getValue : function(){
11044 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11047 if(this.valueField){
11048 return typeof this.value != 'undefined' ? this.value : '';
11050 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11055 * Clears any text/value currently set in the field
11057 clearValue : function(){
11058 if(this.hiddenField){
11059 this.hiddenField.dom.value = '';
11062 this.setRawValue('');
11063 this.lastSelectionText = '';
11068 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11069 * will be displayed in the field. If the value does not match the data value of an existing item,
11070 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11071 * Otherwise the field will be blank (although the value will still be set).
11072 * @param {String} value The value to match
11074 setValue : function(v){
11081 if(this.valueField){
11082 var r = this.findRecord(this.valueField, v);
11084 text = r.data[this.displayField];
11085 }else if(this.valueNotFoundText !== undefined){
11086 text = this.valueNotFoundText;
11089 this.lastSelectionText = text;
11090 if(this.hiddenField){
11091 this.hiddenField.dom.value = v;
11093 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11097 * @property {Object} the last set data for the element
11102 * Sets the value of the field based on a object which is related to the record format for the store.
11103 * @param {Object} value the value to set as. or false on reset?
11105 setFromData : function(o){
11108 // if(typeof o.display_name !== 'string'){
11109 // for(var i=0;i<o.display_name.length;i++){
11110 // this.addItem({'id':o.id[i],'display_name':o.display_name[i]});
11117 var dv = ''; // display value
11118 var vv = ''; // value value..
11120 if (this.displayField) {
11121 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11123 // this is an error condition!!!
11124 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11127 if(this.valueField){
11128 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11131 if(this.hiddenField){
11132 this.hiddenField.dom.value = vv;
11134 this.lastSelectionText = dv;
11135 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11139 // no hidden field.. - we store the value in 'value', but still display
11140 // display field!!!!
11141 this.lastSelectionText = dv;
11142 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11148 reset : function(){
11149 // overridden so that last data is reset..
11150 this.setValue(this.originalValue);
11151 this.clearInvalid();
11152 this.lastData = false;
11154 this.view.clearSelections();
11158 findRecord : function(prop, value){
11160 if(this.store.getCount() > 0){
11161 this.store.each(function(r){
11162 if(r.data[prop] == value){
11172 getName: function()
11174 // returns hidden if it's set..
11175 if (!this.rendered) {return ''};
11176 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11180 onViewMove : function(e, t){
11181 this.inKeyMode = false;
11185 onViewOver : function(e, t){
11186 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11189 var item = this.view.findItemFromChild(t);
11192 var index = this.view.indexOf(item);
11193 this.select(index, false);
11198 onViewClick : function(view, doFocus, el, e)
11200 var index = this.view.getSelectedIndexes()[0];
11202 var r = this.store.getAt(index);
11206 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11213 Roo.each(this.tickItems, function(v,k){
11215 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11216 _this.tickItems.splice(k, 1);
11226 this.tickItems.push(r.data);
11231 this.onSelect(r, index);
11233 if(doFocus !== false && !this.blockFocus){
11234 this.inputEl().focus();
11239 restrictHeight : function(){
11240 //this.innerList.dom.style.height = '';
11241 //var inner = this.innerList.dom;
11242 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11243 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11244 //this.list.beginUpdate();
11245 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11246 this.list.alignTo(this.inputEl(), this.listAlign);
11247 this.list.alignTo(this.inputEl(), this.listAlign);
11248 //this.list.endUpdate();
11252 onEmptyResults : function(){
11257 * Returns true if the dropdown list is expanded, else false.
11259 isExpanded : function(){
11260 return this.list.isVisible();
11264 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11265 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11266 * @param {String} value The data value of the item to select
11267 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11268 * selected item if it is not currently in view (defaults to true)
11269 * @return {Boolean} True if the value matched an item in the list, else false
11271 selectByValue : function(v, scrollIntoView){
11272 if(v !== undefined && v !== null){
11273 var r = this.findRecord(this.valueField || this.displayField, v);
11275 this.select(this.store.indexOf(r), scrollIntoView);
11283 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11284 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11285 * @param {Number} index The zero-based index of the list item to select
11286 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11287 * selected item if it is not currently in view (defaults to true)
11289 select : function(index, scrollIntoView){
11290 this.selectedIndex = index;
11291 this.view.select(index);
11292 if(scrollIntoView !== false){
11293 var el = this.view.getNode(index);
11294 if(el && !this.multiple && !this.tickable){
11295 this.list.scrollChildIntoView(el, false);
11301 selectNext : function(){
11302 var ct = this.store.getCount();
11304 if(this.selectedIndex == -1){
11306 }else if(this.selectedIndex < ct-1){
11307 this.select(this.selectedIndex+1);
11313 selectPrev : function(){
11314 var ct = this.store.getCount();
11316 if(this.selectedIndex == -1){
11318 }else if(this.selectedIndex != 0){
11319 this.select(this.selectedIndex-1);
11325 onKeyUp : function(e){
11326 if(this.editable !== false && !e.isSpecialKey()){
11327 this.lastKey = e.getKey();
11328 this.dqTask.delay(this.queryDelay);
11333 validateBlur : function(){
11334 return !this.list || !this.list.isVisible();
11338 initQuery : function(){
11339 this.doQuery(this.getRawValue());
11343 doForce : function(){
11344 if(this.inputEl().dom.value.length > 0){
11345 this.inputEl().dom.value =
11346 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11352 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11353 * query allowing the query action to be canceled if needed.
11354 * @param {String} query The SQL query to execute
11355 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11356 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11357 * saved in the current store (defaults to false)
11359 doQuery : function(q, forceAll){
11361 if(q === undefined || q === null){
11366 forceAll: forceAll,
11370 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11375 forceAll = qe.forceAll;
11376 if(forceAll === true || (q.length >= this.minChars)){
11378 this.hasQuery = true;
11380 if(this.lastQuery != q || this.alwaysQuery){
11381 this.lastQuery = q;
11382 if(this.mode == 'local'){
11383 this.selectedIndex = -1;
11385 this.store.clearFilter();
11387 this.store.filter(this.displayField, q);
11391 this.store.baseParams[this.queryParam] = q;
11393 var options = {params : this.getParams(q)};
11396 options.add = true;
11397 options.params.start = this.page * this.pageSize;
11400 this.store.load(options);
11402 * this code will make the page width larger, at the beginning, the list not align correctly,
11403 * we should expand the list on onLoad
11404 * so command out it
11409 this.selectedIndex = -1;
11414 this.loadNext = false;
11418 getParams : function(q){
11420 //p[this.queryParam] = q;
11424 p.limit = this.pageSize;
11430 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11432 collapse : function(){
11433 if(!this.isExpanded()){
11437 this.hasFocus = false;
11443 this.cancelBtn.hide();
11444 this.trigger.show();
11447 Roo.get(document).un('mousedown', this.collapseIf, this);
11448 Roo.get(document).un('mousewheel', this.collapseIf, this);
11449 if (!this.editable) {
11450 Roo.get(document).un('keydown', this.listKeyPress, this);
11452 this.fireEvent('collapse', this);
11456 collapseIf : function(e){
11457 var in_combo = e.within(this.el);
11458 var in_list = e.within(this.list);
11459 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11461 if (in_combo || in_list || is_list) {
11462 //e.stopPropagation();
11467 this.onTickableFooterButtonClick(e, false, false);
11475 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11477 expand : function(){
11479 if(this.isExpanded() || !this.hasFocus){
11486 this.restrictHeight();
11490 this.tickItems = Roo.apply([], this.item);
11493 this.cancelBtn.show();
11494 this.trigger.hide();
11498 Roo.get(document).on('mousedown', this.collapseIf, this);
11499 Roo.get(document).on('mousewheel', this.collapseIf, this);
11500 if (!this.editable) {
11501 Roo.get(document).on('keydown', this.listKeyPress, this);
11504 this.fireEvent('expand', this);
11508 // Implements the default empty TriggerField.onTriggerClick function
11509 onTriggerClick : function(e)
11511 Roo.log('trigger click');
11513 if(this.disabled || !this.triggerList){
11518 this.loadNext = false;
11520 if(this.isExpanded()){
11522 if (!this.blockFocus) {
11523 this.inputEl().focus();
11527 this.hasFocus = true;
11528 if(this.triggerAction == 'all') {
11529 this.doQuery(this.allQuery, true);
11531 this.doQuery(this.getRawValue());
11533 if (!this.blockFocus) {
11534 this.inputEl().focus();
11539 onTickableTriggerClick : function(e)
11546 this.loadNext = false;
11547 this.hasFocus = true;
11549 if(this.triggerAction == 'all') {
11550 this.doQuery(this.allQuery, true);
11552 this.doQuery(this.getRawValue());
11556 onSearchFieldClick : function(e)
11558 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11563 this.loadNext = false;
11564 this.hasFocus = true;
11566 if(this.triggerAction == 'all') {
11567 this.doQuery(this.allQuery, true);
11569 this.doQuery(this.getRawValue());
11573 listKeyPress : function(e)
11575 //Roo.log('listkeypress');
11576 // scroll to first matching element based on key pres..
11577 if (e.isSpecialKey()) {
11580 var k = String.fromCharCode(e.getKey()).toUpperCase();
11583 var csel = this.view.getSelectedNodes();
11584 var cselitem = false;
11586 var ix = this.view.indexOf(csel[0]);
11587 cselitem = this.store.getAt(ix);
11588 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11594 this.store.each(function(v) {
11596 // start at existing selection.
11597 if (cselitem.id == v.id) {
11603 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11604 match = this.store.indexOf(v);
11610 if (match === false) {
11611 return true; // no more action?
11614 this.view.select(match);
11615 var sn = Roo.get(this.view.getSelectedNodes()[0])
11616 //sn.scrollIntoView(sn.dom.parentNode, false);
11619 onViewScroll : function(e, t){
11621 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
11625 this.hasQuery = true;
11627 this.loading = this.list.select('.loading', true).first();
11629 if(this.loading === null){
11630 this.list.createChild({
11632 cls: 'loading select2-more-results select2-active',
11633 html: 'Loading more results...'
11636 this.loading = this.list.select('.loading', true).first();
11638 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11640 this.loading.hide();
11643 this.loading.show();
11648 this.loadNext = true;
11650 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11655 addItem : function(o)
11657 var dv = ''; // display value
11659 if (this.displayField) {
11660 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11662 // this is an error condition!!!
11663 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11670 var choice = this.choices.createChild({
11672 cls: 'select2-search-choice',
11681 cls: 'select2-search-choice-close',
11686 }, this.searchField);
11688 var close = choice.select('a.select2-search-choice-close', true).first()
11690 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11698 this.inputEl().dom.value = '';
11702 onRemoveItem : function(e, _self, o)
11704 e.preventDefault();
11705 var index = this.item.indexOf(o.data) * 1;
11708 Roo.log('not this item?!');
11712 this.item.splice(index, 1);
11717 this.fireEvent('remove', this, e);
11721 syncValue : function()
11723 if(!this.item.length){
11730 Roo.each(this.item, function(i){
11731 if(_this.valueField){
11732 value.push(i[_this.valueField]);
11739 this.value = value.join(',');
11741 if(this.hiddenField){
11742 this.hiddenField.dom.value = this.value;
11746 clearItem : function()
11748 if(!this.multiple){
11754 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11761 inputEl: function ()
11764 return this.searchField;
11766 return this.el.select('input.form-control',true).first();
11770 onTickableFooterButtonClick : function(e, btn, el)
11772 e.preventDefault();
11774 if(btn && btn.name == 'cancel'){
11775 this.tickItems = Roo.apply([], this.item);
11784 Roo.each(this.tickItems, function(o){
11795 * @cfg {Boolean} grow
11799 * @cfg {Number} growMin
11803 * @cfg {Number} growMax
11813 * Ext JS Library 1.1.1
11814 * Copyright(c) 2006-2007, Ext JS, LLC.
11816 * Originally Released Under LGPL - original licence link has changed is not relivant.
11819 * <script type="text/javascript">
11824 * @extends Roo.util.Observable
11825 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11826 * This class also supports single and multi selection modes. <br>
11827 * Create a data model bound view:
11829 var store = new Roo.data.Store(...);
11831 var view = new Roo.View({
11833 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11835 singleSelect: true,
11836 selectedClass: "ydataview-selected",
11840 // listen for node click?
11841 view.on("click", function(vw, index, node, e){
11842 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
11846 dataModel.load("foobar.xml");
11848 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
11850 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
11851 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
11853 * Note: old style constructor is still suported (container, template, config)
11856 * Create a new View
11857 * @param {Object} config The config object
11860 Roo.View = function(config, depreciated_tpl, depreciated_config){
11862 this.parent = false;
11864 if (typeof(depreciated_tpl) == 'undefined') {
11865 // new way.. - universal constructor.
11866 Roo.apply(this, config);
11867 this.el = Roo.get(this.el);
11870 this.el = Roo.get(config);
11871 this.tpl = depreciated_tpl;
11872 Roo.apply(this, depreciated_config);
11874 this.wrapEl = this.el.wrap().wrap();
11875 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
11878 if(typeof(this.tpl) == "string"){
11879 this.tpl = new Roo.Template(this.tpl);
11881 // support xtype ctors..
11882 this.tpl = new Roo.factory(this.tpl, Roo);
11886 this.tpl.compile();
11891 * @event beforeclick
11892 * Fires before a click is processed. Returns false to cancel the default action.
11893 * @param {Roo.View} this
11894 * @param {Number} index The index of the target node
11895 * @param {HTMLElement} node The target node
11896 * @param {Roo.EventObject} e The raw event object
11898 "beforeclick" : true,
11901 * Fires when a template node is clicked.
11902 * @param {Roo.View} this
11903 * @param {Number} index The index of the target node
11904 * @param {HTMLElement} node The target node
11905 * @param {Roo.EventObject} e The raw event object
11910 * Fires when a template node is double clicked.
11911 * @param {Roo.View} this
11912 * @param {Number} index The index of the target node
11913 * @param {HTMLElement} node The target node
11914 * @param {Roo.EventObject} e The raw event object
11918 * @event contextmenu
11919 * Fires when a template node is right clicked.
11920 * @param {Roo.View} this
11921 * @param {Number} index The index of the target node
11922 * @param {HTMLElement} node The target node
11923 * @param {Roo.EventObject} e The raw event object
11925 "contextmenu" : true,
11927 * @event selectionchange
11928 * Fires when the selected nodes change.
11929 * @param {Roo.View} this
11930 * @param {Array} selections Array of the selected nodes
11932 "selectionchange" : true,
11935 * @event beforeselect
11936 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
11937 * @param {Roo.View} this
11938 * @param {HTMLElement} node The node to be selected
11939 * @param {Array} selections Array of currently selected nodes
11941 "beforeselect" : true,
11943 * @event preparedata
11944 * Fires on every row to render, to allow you to change the data.
11945 * @param {Roo.View} this
11946 * @param {Object} data to be rendered (change this)
11948 "preparedata" : true
11956 "click": this.onClick,
11957 "dblclick": this.onDblClick,
11958 "contextmenu": this.onContextMenu,
11962 this.selections = [];
11964 this.cmp = new Roo.CompositeElementLite([]);
11966 this.store = Roo.factory(this.store, Roo.data);
11967 this.setStore(this.store, true);
11970 if ( this.footer && this.footer.xtype) {
11972 var fctr = this.wrapEl.appendChild(document.createElement("div"));
11974 this.footer.dataSource = this.store
11975 this.footer.container = fctr;
11976 this.footer = Roo.factory(this.footer, Roo);
11977 fctr.insertFirst(this.el);
11979 // this is a bit insane - as the paging toolbar seems to detach the el..
11980 // dom.parentNode.parentNode.parentNode
11981 // they get detached?
11985 Roo.View.superclass.constructor.call(this);
11990 Roo.extend(Roo.View, Roo.util.Observable, {
11993 * @cfg {Roo.data.Store} store Data store to load data from.
11998 * @cfg {String|Roo.Element} el The container element.
12003 * @cfg {String|Roo.Template} tpl The template used by this View
12007 * @cfg {String} dataName the named area of the template to use as the data area
12008 * Works with domtemplates roo-name="name"
12012 * @cfg {String} selectedClass The css class to add to selected nodes
12014 selectedClass : "x-view-selected",
12016 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12021 * @cfg {String} text to display on mask (default Loading)
12025 * @cfg {Boolean} multiSelect Allow multiple selection
12027 multiSelect : false,
12029 * @cfg {Boolean} singleSelect Allow single selection
12031 singleSelect: false,
12034 * @cfg {Boolean} toggleSelect - selecting
12036 toggleSelect : false,
12039 * @cfg {Boolean} tickable - selecting
12044 * Returns the element this view is bound to.
12045 * @return {Roo.Element}
12047 getEl : function(){
12048 return this.wrapEl;
12054 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12056 refresh : function(){
12057 Roo.log('refresh');
12060 // if we are using something like 'domtemplate', then
12061 // the what gets used is:
12062 // t.applySubtemplate(NAME, data, wrapping data..)
12063 // the outer template then get' applied with
12064 // the store 'extra data'
12065 // and the body get's added to the
12066 // roo-name="data" node?
12067 // <span class='roo-tpl-{name}'></span> ?????
12071 this.clearSelections();
12072 this.el.update("");
12074 var records = this.store.getRange();
12075 if(records.length < 1) {
12077 // is this valid?? = should it render a template??
12079 this.el.update(this.emptyText);
12083 if (this.dataName) {
12084 this.el.update(t.apply(this.store.meta)); //????
12085 el = this.el.child('.roo-tpl-' + this.dataName);
12088 for(var i = 0, len = records.length; i < len; i++){
12089 var data = this.prepareData(records[i].data, i, records[i]);
12090 this.fireEvent("preparedata", this, data, i, records[i]);
12092 var d = Roo.apply({}, data);
12095 Roo.apply(d, {'roo-id' : Roo.id()});
12099 Roo.each(this.parent.item, function(item){
12100 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12103 Roo.apply(d, {'roo-data-checked' : 'checked'});
12107 html[html.length] = Roo.util.Format.trim(
12109 t.applySubtemplate(this.dataName, d, this.store.meta) :
12116 el.update(html.join(""));
12117 this.nodes = el.dom.childNodes;
12118 this.updateIndexes(0);
12123 * Function to override to reformat the data that is sent to
12124 * the template for each node.
12125 * DEPRICATED - use the preparedata event handler.
12126 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12127 * a JSON object for an UpdateManager bound view).
12129 prepareData : function(data, index, record)
12131 this.fireEvent("preparedata", this, data, index, record);
12135 onUpdate : function(ds, record){
12136 Roo.log('on update');
12137 this.clearSelections();
12138 var index = this.store.indexOf(record);
12139 var n = this.nodes[index];
12140 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12141 n.parentNode.removeChild(n);
12142 this.updateIndexes(index, index);
12148 onAdd : function(ds, records, index)
12150 Roo.log(['on Add', ds, records, index] );
12151 this.clearSelections();
12152 if(this.nodes.length == 0){
12156 var n = this.nodes[index];
12157 for(var i = 0, len = records.length; i < len; i++){
12158 var d = this.prepareData(records[i].data, i, records[i]);
12160 this.tpl.insertBefore(n, d);
12163 this.tpl.append(this.el, d);
12166 this.updateIndexes(index);
12169 onRemove : function(ds, record, index){
12170 Roo.log('onRemove');
12171 this.clearSelections();
12172 var el = this.dataName ?
12173 this.el.child('.roo-tpl-' + this.dataName) :
12176 el.dom.removeChild(this.nodes[index]);
12177 this.updateIndexes(index);
12181 * Refresh an individual node.
12182 * @param {Number} index
12184 refreshNode : function(index){
12185 this.onUpdate(this.store, this.store.getAt(index));
12188 updateIndexes : function(startIndex, endIndex){
12189 var ns = this.nodes;
12190 startIndex = startIndex || 0;
12191 endIndex = endIndex || ns.length - 1;
12192 for(var i = startIndex; i <= endIndex; i++){
12193 ns[i].nodeIndex = i;
12198 * Changes the data store this view uses and refresh the view.
12199 * @param {Store} store
12201 setStore : function(store, initial){
12202 if(!initial && this.store){
12203 this.store.un("datachanged", this.refresh);
12204 this.store.un("add", this.onAdd);
12205 this.store.un("remove", this.onRemove);
12206 this.store.un("update", this.onUpdate);
12207 this.store.un("clear", this.refresh);
12208 this.store.un("beforeload", this.onBeforeLoad);
12209 this.store.un("load", this.onLoad);
12210 this.store.un("loadexception", this.onLoad);
12214 store.on("datachanged", this.refresh, this);
12215 store.on("add", this.onAdd, this);
12216 store.on("remove", this.onRemove, this);
12217 store.on("update", this.onUpdate, this);
12218 store.on("clear", this.refresh, this);
12219 store.on("beforeload", this.onBeforeLoad, this);
12220 store.on("load", this.onLoad, this);
12221 store.on("loadexception", this.onLoad, this);
12229 * onbeforeLoad - masks the loading area.
12232 onBeforeLoad : function(store,opts)
12234 Roo.log('onBeforeLoad');
12236 this.el.update("");
12238 this.el.mask(this.mask ? this.mask : "Loading" );
12240 onLoad : function ()
12247 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12248 * @param {HTMLElement} node
12249 * @return {HTMLElement} The template node
12251 findItemFromChild : function(node){
12252 var el = this.dataName ?
12253 this.el.child('.roo-tpl-' + this.dataName,true) :
12256 if(!node || node.parentNode == el){
12259 var p = node.parentNode;
12260 while(p && p != el){
12261 if(p.parentNode == el){
12270 onClick : function(e){
12271 var item = this.findItemFromChild(e.getTarget());
12273 var index = this.indexOf(item);
12274 if(this.onItemClick(item, index, e) !== false){
12275 this.fireEvent("click", this, index, item, e);
12278 this.clearSelections();
12283 onContextMenu : function(e){
12284 var item = this.findItemFromChild(e.getTarget());
12286 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12291 onDblClick : function(e){
12292 var item = this.findItemFromChild(e.getTarget());
12294 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12298 onItemClick : function(item, index, e)
12300 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12303 if (this.toggleSelect) {
12304 var m = this.isSelected(item) ? 'unselect' : 'select';
12307 _t[m](item, true, false);
12310 if(this.multiSelect || this.singleSelect){
12311 if(this.multiSelect && e.shiftKey && this.lastSelection){
12312 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12314 this.select(item, this.multiSelect && e.ctrlKey);
12315 this.lastSelection = item;
12318 if(!this.tickable){
12319 e.preventDefault();
12327 * Get the number of selected nodes.
12330 getSelectionCount : function(){
12331 return this.selections.length;
12335 * Get the currently selected nodes.
12336 * @return {Array} An array of HTMLElements
12338 getSelectedNodes : function(){
12339 return this.selections;
12343 * Get the indexes of the selected nodes.
12346 getSelectedIndexes : function(){
12347 var indexes = [], s = this.selections;
12348 for(var i = 0, len = s.length; i < len; i++){
12349 indexes.push(s[i].nodeIndex);
12355 * Clear all selections
12356 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12358 clearSelections : function(suppressEvent){
12359 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12360 this.cmp.elements = this.selections;
12361 this.cmp.removeClass(this.selectedClass);
12362 this.selections = [];
12363 if(!suppressEvent){
12364 this.fireEvent("selectionchange", this, this.selections);
12370 * Returns true if the passed node is selected
12371 * @param {HTMLElement/Number} node The node or node index
12372 * @return {Boolean}
12374 isSelected : function(node){
12375 var s = this.selections;
12379 node = this.getNode(node);
12380 return s.indexOf(node) !== -1;
12385 * @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
12386 * @param {Boolean} keepExisting (optional) true to keep existing selections
12387 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12389 select : function(nodeInfo, keepExisting, suppressEvent){
12390 if(nodeInfo instanceof Array){
12392 this.clearSelections(true);
12394 for(var i = 0, len = nodeInfo.length; i < len; i++){
12395 this.select(nodeInfo[i], true, true);
12399 var node = this.getNode(nodeInfo);
12400 if(!node || this.isSelected(node)){
12401 return; // already selected.
12404 this.clearSelections(true);
12406 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12407 Roo.fly(node).addClass(this.selectedClass);
12408 this.selections.push(node);
12409 if(!suppressEvent){
12410 this.fireEvent("selectionchange", this, this.selections);
12418 * @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
12419 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12420 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12422 unselect : function(nodeInfo, keepExisting, suppressEvent)
12424 if(nodeInfo instanceof Array){
12425 Roo.each(this.selections, function(s) {
12426 this.unselect(s, nodeInfo);
12430 var node = this.getNode(nodeInfo);
12431 if(!node || !this.isSelected(node)){
12432 Roo.log("not selected");
12433 return; // not selected.
12437 Roo.each(this.selections, function(s) {
12439 Roo.fly(node).removeClass(this.selectedClass);
12446 this.selections= ns;
12447 this.fireEvent("selectionchange", this, this.selections);
12451 * Gets a template node.
12452 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12453 * @return {HTMLElement} The node or null if it wasn't found
12455 getNode : function(nodeInfo){
12456 if(typeof nodeInfo == "string"){
12457 return document.getElementById(nodeInfo);
12458 }else if(typeof nodeInfo == "number"){
12459 return this.nodes[nodeInfo];
12465 * Gets a range template nodes.
12466 * @param {Number} startIndex
12467 * @param {Number} endIndex
12468 * @return {Array} An array of nodes
12470 getNodes : function(start, end){
12471 var ns = this.nodes;
12472 start = start || 0;
12473 end = typeof end == "undefined" ? ns.length - 1 : end;
12476 for(var i = start; i <= end; i++){
12480 for(var i = start; i >= end; i--){
12488 * Finds the index of the passed node
12489 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12490 * @return {Number} The index of the node or -1
12492 indexOf : function(node){
12493 node = this.getNode(node);
12494 if(typeof node.nodeIndex == "number"){
12495 return node.nodeIndex;
12497 var ns = this.nodes;
12498 for(var i = 0, len = ns.length; i < len; i++){
12509 * based on jquery fullcalendar
12513 Roo.bootstrap = Roo.bootstrap || {};
12515 * @class Roo.bootstrap.Calendar
12516 * @extends Roo.bootstrap.Component
12517 * Bootstrap Calendar class
12518 * @cfg {Boolean} loadMask (true|false) default false
12519 * @cfg {Object} header generate the user specific header of the calendar, default false
12522 * Create a new Container
12523 * @param {Object} config The config object
12528 Roo.bootstrap.Calendar = function(config){
12529 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12533 * Fires when a date is selected
12534 * @param {DatePicker} this
12535 * @param {Date} date The selected date
12539 * @event monthchange
12540 * Fires when the displayed month changes
12541 * @param {DatePicker} this
12542 * @param {Date} date The selected month
12544 'monthchange': true,
12546 * @event evententer
12547 * Fires when mouse over an event
12548 * @param {Calendar} this
12549 * @param {event} Event
12551 'evententer': true,
12553 * @event eventleave
12554 * Fires when the mouse leaves an
12555 * @param {Calendar} this
12558 'eventleave': true,
12560 * @event eventclick
12561 * Fires when the mouse click an
12562 * @param {Calendar} this
12571 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12574 * @cfg {Number} startDay
12575 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12583 getAutoCreate : function(){
12586 var fc_button = function(name, corner, style, content ) {
12587 return Roo.apply({},{
12589 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12591 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12594 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12605 style : 'width:100%',
12612 cls : 'fc-header-left',
12614 fc_button('prev', 'left', 'arrow', '‹' ),
12615 fc_button('next', 'right', 'arrow', '›' ),
12616 { tag: 'span', cls: 'fc-header-space' },
12617 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12625 cls : 'fc-header-center',
12629 cls: 'fc-header-title',
12632 html : 'month / year'
12640 cls : 'fc-header-right',
12642 /* fc_button('month', 'left', '', 'month' ),
12643 fc_button('week', '', '', 'week' ),
12644 fc_button('day', 'right', '', 'day' )
12656 header = this.header;
12659 var cal_heads = function() {
12661 // fixme - handle this.
12663 for (var i =0; i < Date.dayNames.length; i++) {
12664 var d = Date.dayNames[i];
12667 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12668 html : d.substring(0,3)
12672 ret[0].cls += ' fc-first';
12673 ret[6].cls += ' fc-last';
12676 var cal_cell = function(n) {
12679 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12684 cls: 'fc-day-number',
12688 cls: 'fc-day-content',
12692 style: 'position: relative;' // height: 17px;
12704 var cal_rows = function() {
12707 for (var r = 0; r < 6; r++) {
12714 for (var i =0; i < Date.dayNames.length; i++) {
12715 var d = Date.dayNames[i];
12716 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12719 row.cn[0].cls+=' fc-first';
12720 row.cn[0].cn[0].style = 'min-height:90px';
12721 row.cn[6].cls+=' fc-last';
12725 ret[0].cls += ' fc-first';
12726 ret[4].cls += ' fc-prev-last';
12727 ret[5].cls += ' fc-last';
12734 cls: 'fc-border-separate',
12735 style : 'width:100%',
12743 cls : 'fc-first fc-last',
12761 cls : 'fc-content',
12762 style : "position: relative;",
12765 cls : 'fc-view fc-view-month fc-grid',
12766 style : 'position: relative',
12767 unselectable : 'on',
12770 cls : 'fc-event-container',
12771 style : 'position:absolute;z-index:8;top:0;left:0;'
12789 initEvents : function()
12792 throw "can not find store for calendar";
12798 style: "text-align:center",
12802 style: "background-color:white;width:50%;margin:250 auto",
12806 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12817 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12819 var size = this.el.select('.fc-content', true).first().getSize();
12820 this.maskEl.setSize(size.width, size.height);
12821 this.maskEl.enableDisplayMode("block");
12822 if(!this.loadMask){
12823 this.maskEl.hide();
12826 this.store = Roo.factory(this.store, Roo.data);
12827 this.store.on('load', this.onLoad, this);
12828 this.store.on('beforeload', this.onBeforeLoad, this);
12832 this.cells = this.el.select('.fc-day',true);
12833 //Roo.log(this.cells);
12834 this.textNodes = this.el.query('.fc-day-number');
12835 this.cells.addClassOnOver('fc-state-hover');
12837 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12838 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12839 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12840 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12842 this.on('monthchange', this.onMonthChange, this);
12844 this.update(new Date().clearTime());
12847 resize : function() {
12848 var sz = this.el.getSize();
12850 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
12851 this.el.select('.fc-day-content div',true).setHeight(34);
12856 showPrevMonth : function(e){
12857 this.update(this.activeDate.add("mo", -1));
12859 showToday : function(e){
12860 this.update(new Date().clearTime());
12863 showNextMonth : function(e){
12864 this.update(this.activeDate.add("mo", 1));
12868 showPrevYear : function(){
12869 this.update(this.activeDate.add("y", -1));
12873 showNextYear : function(){
12874 this.update(this.activeDate.add("y", 1));
12879 update : function(date)
12881 var vd = this.activeDate;
12882 this.activeDate = date;
12883 // if(vd && this.el){
12884 // var t = date.getTime();
12885 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
12886 // Roo.log('using add remove');
12888 // this.fireEvent('monthchange', this, date);
12890 // this.cells.removeClass("fc-state-highlight");
12891 // this.cells.each(function(c){
12892 // if(c.dateValue == t){
12893 // c.addClass("fc-state-highlight");
12894 // setTimeout(function(){
12895 // try{c.dom.firstChild.focus();}catch(e){}
12905 var days = date.getDaysInMonth();
12907 var firstOfMonth = date.getFirstDateOfMonth();
12908 var startingPos = firstOfMonth.getDay()-this.startDay;
12910 if(startingPos < this.startDay){
12914 var pm = date.add(Date.MONTH, -1);
12915 var prevStart = pm.getDaysInMonth()-startingPos;
12917 this.cells = this.el.select('.fc-day',true);
12918 this.textNodes = this.el.query('.fc-day-number');
12919 this.cells.addClassOnOver('fc-state-hover');
12921 var cells = this.cells.elements;
12922 var textEls = this.textNodes;
12924 Roo.each(cells, function(cell){
12925 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
12928 days += startingPos;
12930 // convert everything to numbers so it's fast
12931 var day = 86400000;
12932 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
12935 //Roo.log(prevStart);
12937 var today = new Date().clearTime().getTime();
12938 var sel = date.clearTime().getTime();
12939 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
12940 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
12941 var ddMatch = this.disabledDatesRE;
12942 var ddText = this.disabledDatesText;
12943 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
12944 var ddaysText = this.disabledDaysText;
12945 var format = this.format;
12947 var setCellClass = function(cal, cell){
12951 //Roo.log('set Cell Class');
12953 var t = d.getTime();
12957 cell.dateValue = t;
12959 cell.className += " fc-today";
12960 cell.className += " fc-state-highlight";
12961 cell.title = cal.todayText;
12964 // disable highlight in other month..
12965 //cell.className += " fc-state-highlight";
12970 cell.className = " fc-state-disabled";
12971 cell.title = cal.minText;
12975 cell.className = " fc-state-disabled";
12976 cell.title = cal.maxText;
12980 if(ddays.indexOf(d.getDay()) != -1){
12981 cell.title = ddaysText;
12982 cell.className = " fc-state-disabled";
12985 if(ddMatch && format){
12986 var fvalue = d.dateFormat(format);
12987 if(ddMatch.test(fvalue)){
12988 cell.title = ddText.replace("%0", fvalue);
12989 cell.className = " fc-state-disabled";
12993 if (!cell.initialClassName) {
12994 cell.initialClassName = cell.dom.className;
12997 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13002 for(; i < startingPos; i++) {
13003 textEls[i].innerHTML = (++prevStart);
13004 d.setDate(d.getDate()+1);
13006 cells[i].className = "fc-past fc-other-month";
13007 setCellClass(this, cells[i]);
13012 for(; i < days; i++){
13013 intDay = i - startingPos + 1;
13014 textEls[i].innerHTML = (intDay);
13015 d.setDate(d.getDate()+1);
13017 cells[i].className = ''; // "x-date-active";
13018 setCellClass(this, cells[i]);
13022 for(; i < 42; i++) {
13023 textEls[i].innerHTML = (++extraDays);
13024 d.setDate(d.getDate()+1);
13026 cells[i].className = "fc-future fc-other-month";
13027 setCellClass(this, cells[i]);
13030 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13032 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13034 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13035 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13037 if(totalRows != 6){
13038 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13039 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13042 this.fireEvent('monthchange', this, date);
13046 if(!this.internalRender){
13047 var main = this.el.dom.firstChild;
13048 var w = main.offsetWidth;
13049 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13050 Roo.fly(main).setWidth(w);
13051 this.internalRender = true;
13052 // opera does not respect the auto grow header center column
13053 // then, after it gets a width opera refuses to recalculate
13054 // without a second pass
13055 if(Roo.isOpera && !this.secondPass){
13056 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13057 this.secondPass = true;
13058 this.update.defer(10, this, [date]);
13065 findCell : function(dt) {
13066 dt = dt.clearTime().getTime();
13068 this.cells.each(function(c){
13069 //Roo.log("check " +c.dateValue + '?=' + dt);
13070 if(c.dateValue == dt){
13080 findCells : function(ev) {
13081 var s = ev.start.clone().clearTime().getTime();
13083 var e= ev.end.clone().clearTime().getTime();
13086 this.cells.each(function(c){
13087 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13089 if(c.dateValue > e){
13092 if(c.dateValue < s){
13101 // findBestRow: function(cells)
13105 // for (var i =0 ; i < cells.length;i++) {
13106 // ret = Math.max(cells[i].rows || 0,ret);
13113 addItem : function(ev)
13115 // look for vertical location slot in
13116 var cells = this.findCells(ev);
13118 // ev.row = this.findBestRow(cells);
13120 // work out the location.
13124 for(var i =0; i < cells.length; i++) {
13126 cells[i].row = cells[0].row;
13129 cells[i].row = cells[i].row + 1;
13139 if (crow.start.getY() == cells[i].getY()) {
13141 crow.end = cells[i];
13158 cells[0].events.push(ev);
13160 this.calevents.push(ev);
13163 clearEvents: function() {
13165 if(!this.calevents){
13169 Roo.each(this.cells.elements, function(c){
13175 Roo.each(this.calevents, function(e) {
13176 Roo.each(e.els, function(el) {
13177 el.un('mouseenter' ,this.onEventEnter, this);
13178 el.un('mouseleave' ,this.onEventLeave, this);
13183 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13189 renderEvents: function()
13193 this.cells.each(function(c) {
13202 if(c.row != c.events.length){
13203 r = 4 - (4 - (c.row - c.events.length));
13206 c.events = ev.slice(0, r);
13207 c.more = ev.slice(r);
13209 if(c.more.length && c.more.length == 1){
13210 c.events.push(c.more.pop());
13213 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13217 this.cells.each(function(c) {
13219 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13222 for (var e = 0; e < c.events.length; e++){
13223 var ev = c.events[e];
13224 var rows = ev.rows;
13226 for(var i = 0; i < rows.length; i++) {
13228 // how many rows should it span..
13231 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13232 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13234 unselectable : "on",
13237 cls: 'fc-event-inner',
13241 // cls: 'fc-event-time',
13242 // html : cells.length > 1 ? '' : ev.time
13246 cls: 'fc-event-title',
13247 html : String.format('{0}', ev.title)
13254 cls: 'ui-resizable-handle ui-resizable-e',
13255 html : '  '
13262 cfg.cls += ' fc-event-start';
13264 if ((i+1) == rows.length) {
13265 cfg.cls += ' fc-event-end';
13268 var ctr = _this.el.select('.fc-event-container',true).first();
13269 var cg = ctr.createChild(cfg);
13271 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13272 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13274 var r = (c.more.length) ? 1 : 0;
13275 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13276 cg.setWidth(ebox.right - sbox.x -2);
13278 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13279 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13280 cg.on('click', _this.onEventClick, _this, ev);
13291 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13292 style : 'position: absolute',
13293 unselectable : "on",
13296 cls: 'fc-event-inner',
13300 cls: 'fc-event-title',
13308 cls: 'ui-resizable-handle ui-resizable-e',
13309 html : '  '
13315 var ctr = _this.el.select('.fc-event-container',true).first();
13316 var cg = ctr.createChild(cfg);
13318 var sbox = c.select('.fc-day-content',true).first().getBox();
13319 var ebox = c.select('.fc-day-content',true).first().getBox();
13321 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13322 cg.setWidth(ebox.right - sbox.x -2);
13324 cg.on('click', _this.onMoreEventClick, _this, c.more);
13334 onEventEnter: function (e, el,event,d) {
13335 this.fireEvent('evententer', this, el, event);
13338 onEventLeave: function (e, el,event,d) {
13339 this.fireEvent('eventleave', this, el, event);
13342 onEventClick: function (e, el,event,d) {
13343 this.fireEvent('eventclick', this, el, event);
13346 onMonthChange: function () {
13350 onMoreEventClick: function(e, el, more)
13354 this.calpopover.placement = 'right';
13355 this.calpopover.setTitle('More');
13357 this.calpopover.setContent('');
13359 var ctr = this.calpopover.el.select('.popover-content', true).first();
13361 Roo.each(more, function(m){
13363 cls : 'fc-event-hori fc-event-draggable',
13366 var cg = ctr.createChild(cfg);
13368 cg.on('click', _this.onEventClick, _this, m);
13371 this.calpopover.show(el);
13376 onLoad: function ()
13378 this.calevents = [];
13381 if(this.store.getCount() > 0){
13382 this.store.data.each(function(d){
13385 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13386 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13387 time : d.data.start_time,
13388 title : d.data.title,
13389 description : d.data.description,
13390 venue : d.data.venue
13395 this.renderEvents();
13397 if(this.calevents.length && this.loadMask){
13398 this.maskEl.hide();
13402 onBeforeLoad: function()
13404 this.clearEvents();
13406 this.maskEl.show();
13420 * @class Roo.bootstrap.Popover
13421 * @extends Roo.bootstrap.Component
13422 * Bootstrap Popover class
13423 * @cfg {String} html contents of the popover (or false to use children..)
13424 * @cfg {String} title of popover (or false to hide)
13425 * @cfg {String} placement how it is placed
13426 * @cfg {String} trigger click || hover (or false to trigger manually)
13427 * @cfg {String} over what (parent or false to trigger manually.)
13430 * Create a new Popover
13431 * @param {Object} config The config object
13434 Roo.bootstrap.Popover = function(config){
13435 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13438 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13440 title: 'Fill in a title',
13443 placement : 'right',
13444 trigger : 'hover', // hover
13448 can_build_overlaid : false,
13450 getChildContainer : function()
13452 return this.el.select('.popover-content',true).first();
13455 getAutoCreate : function(){
13456 Roo.log('make popover?');
13458 cls : 'popover roo-dynamic',
13459 style: 'display:block',
13465 cls : 'popover-inner',
13469 cls: 'popover-title',
13473 cls : 'popover-content',
13484 setTitle: function(str)
13486 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13488 setContent: function(str)
13490 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13492 // as it get's added to the bottom of the page.
13493 onRender : function(ct, position)
13495 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13497 var cfg = Roo.apply({}, this.getAutoCreate());
13501 cfg.cls += ' ' + this.cls;
13504 cfg.style = this.style;
13506 Roo.log("adding to ")
13507 this.el = Roo.get(document.body).createChild(cfg, position);
13513 initEvents : function()
13515 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13516 this.el.enableDisplayMode('block');
13518 if (this.over === false) {
13521 if (this.triggers === false) {
13524 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13525 var triggers = this.trigger ? this.trigger.split(' ') : [];
13526 Roo.each(triggers, function(trigger) {
13528 if (trigger == 'click') {
13529 on_el.on('click', this.toggle, this);
13530 } else if (trigger != 'manual') {
13531 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13532 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13534 on_el.on(eventIn ,this.enter, this);
13535 on_el.on(eventOut, this.leave, this);
13546 toggle : function () {
13547 this.hoverState == 'in' ? this.leave() : this.enter();
13550 enter : function () {
13553 clearTimeout(this.timeout);
13555 this.hoverState = 'in'
13557 if (!this.delay || !this.delay.show) {
13562 this.timeout = setTimeout(function () {
13563 if (_t.hoverState == 'in') {
13566 }, this.delay.show)
13568 leave : function() {
13569 clearTimeout(this.timeout);
13571 this.hoverState = 'out'
13573 if (!this.delay || !this.delay.hide) {
13578 this.timeout = setTimeout(function () {
13579 if (_t.hoverState == 'out') {
13582 }, this.delay.hide)
13585 show : function (on_el)
13588 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13591 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13592 if (this.html !== false) {
13593 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13595 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13596 if (!this.title.length) {
13597 this.el.select('.popover-title',true).hide();
13600 var placement = typeof this.placement == 'function' ?
13601 this.placement.call(this, this.el, on_el) :
13604 var autoToken = /\s?auto?\s?/i;
13605 var autoPlace = autoToken.test(placement);
13607 placement = placement.replace(autoToken, '') || 'top';
13611 //this.el.setXY([0,0]);
13613 this.el.dom.style.display='block';
13614 this.el.addClass(placement);
13616 //this.el.appendTo(on_el);
13618 var p = this.getPosition();
13619 var box = this.el.getBox();
13624 var align = Roo.bootstrap.Popover.alignment[placement]
13625 this.el.alignTo(on_el, align[0],align[1]);
13626 //var arrow = this.el.select('.arrow',true).first();
13627 //arrow.set(align[2],
13629 this.el.addClass('in');
13630 this.hoverState = null;
13632 if (this.el.hasClass('fade')) {
13639 this.el.setXY([0,0]);
13640 this.el.removeClass('in');
13647 Roo.bootstrap.Popover.alignment = {
13648 'left' : ['r-l', [-10,0], 'right'],
13649 'right' : ['l-r', [10,0], 'left'],
13650 'bottom' : ['t-b', [0,10], 'top'],
13651 'top' : [ 'b-t', [0,-10], 'bottom']
13662 * @class Roo.bootstrap.Progress
13663 * @extends Roo.bootstrap.Component
13664 * Bootstrap Progress class
13665 * @cfg {Boolean} striped striped of the progress bar
13666 * @cfg {Boolean} active animated of the progress bar
13670 * Create a new Progress
13671 * @param {Object} config The config object
13674 Roo.bootstrap.Progress = function(config){
13675 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13678 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13683 getAutoCreate : function(){
13691 cfg.cls += ' progress-striped';
13695 cfg.cls += ' active';
13714 * @class Roo.bootstrap.ProgressBar
13715 * @extends Roo.bootstrap.Component
13716 * Bootstrap ProgressBar class
13717 * @cfg {Number} aria_valuenow aria-value now
13718 * @cfg {Number} aria_valuemin aria-value min
13719 * @cfg {Number} aria_valuemax aria-value max
13720 * @cfg {String} label label for the progress bar
13721 * @cfg {String} panel (success | info | warning | danger )
13722 * @cfg {String} role role of the progress bar
13723 * @cfg {String} sr_only text
13727 * Create a new ProgressBar
13728 * @param {Object} config The config object
13731 Roo.bootstrap.ProgressBar = function(config){
13732 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13735 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13739 aria_valuemax : 100,
13745 getAutoCreate : function()
13750 cls: 'progress-bar',
13751 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13763 cfg.role = this.role;
13766 if(this.aria_valuenow){
13767 cfg['aria-valuenow'] = this.aria_valuenow;
13770 if(this.aria_valuemin){
13771 cfg['aria-valuemin'] = this.aria_valuemin;
13774 if(this.aria_valuemax){
13775 cfg['aria-valuemax'] = this.aria_valuemax;
13778 if(this.label && !this.sr_only){
13779 cfg.html = this.label;
13783 cfg.cls += ' progress-bar-' + this.panel;
13789 update : function(aria_valuenow)
13791 this.aria_valuenow = aria_valuenow;
13793 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13808 * @class Roo.bootstrap.TabGroup
13809 * @extends Roo.bootstrap.Column
13810 * Bootstrap Column class
13811 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
13812 * @cfg {Boolean} carousel true to make the group behave like a carousel
13815 * Create a new TabGroup
13816 * @param {Object} config The config object
13819 Roo.bootstrap.TabGroup = function(config){
13820 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
13822 this.navId = Roo.id();
13825 Roo.bootstrap.TabGroup.register(this);
13829 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
13832 transition : false,
13834 getAutoCreate : function()
13836 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
13838 cfg.cls += ' tab-content';
13840 if (this.carousel) {
13841 cfg.cls += ' carousel slide';
13843 cls : 'carousel-inner'
13850 getChildContainer : function()
13852 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
13856 * register a Navigation item
13857 * @param {Roo.bootstrap.NavItem} the navitem to add
13859 register : function(item)
13861 this.tabs.push( item);
13862 item.navId = this.navId; // not really needed..
13866 getActivePanel : function()
13869 Roo.each(this.tabs, function(t) {
13879 getPanelByName : function(n)
13882 Roo.each(this.tabs, function(t) {
13883 if (t.tabId == n) {
13891 indexOfPanel : function(p)
13894 Roo.each(this.tabs, function(t,i) {
13895 if (t.tabId == p.tabId) {
13904 * show a specific panel
13905 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
13906 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
13908 showPanel : function (pan)
13911 if (typeof(pan) == 'number') {
13912 pan = this.tabs[pan];
13914 if (typeof(pan) == 'string') {
13915 pan = this.getPanelByName(pan);
13917 if (pan.tabId == this.getActivePanel().tabId) {
13920 var cur = this.getActivePanel();
13922 if (false === cur.fireEvent('beforedeactivate')) {
13926 if (this.carousel) {
13927 this.transition = true;
13928 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
13929 var lr = dir == 'next' ? 'left' : 'right';
13930 pan.el.addClass(dir); // or prev
13931 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
13932 cur.el.addClass(lr); // or right
13933 pan.el.addClass(lr);
13936 cur.el.on('transitionend', function() {
13937 Roo.log("trans end?");
13939 pan.el.removeClass([lr,dir]);
13940 pan.setActive(true);
13942 cur.el.removeClass([lr]);
13943 cur.setActive(false);
13945 _this.transition = false;
13947 }, this, { single: true } );
13951 cur.setActive(false);
13952 pan.setActive(true);
13956 showPanelNext : function()
13958 var i = this.indexOfPanel(this.getActivePanel());
13959 if (i > this.tabs.length) {
13962 this.showPanel(this.tabs[i+1]);
13964 showPanelPrev : function()
13966 var i = this.indexOfPanel(this.getActivePanel());
13970 this.showPanel(this.tabs[i-1]);
13981 Roo.apply(Roo.bootstrap.TabGroup, {
13985 * register a Navigation Group
13986 * @param {Roo.bootstrap.NavGroup} the navgroup to add
13988 register : function(navgrp)
13990 this.groups[navgrp.navId] = navgrp;
13994 * fetch a Navigation Group based on the navigation ID
13995 * if one does not exist , it will get created.
13996 * @param {string} the navgroup to add
13997 * @returns {Roo.bootstrap.NavGroup} the navgroup
13999 get: function(navId) {
14000 if (typeof(this.groups[navId]) == 'undefined') {
14001 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14003 return this.groups[navId] ;
14018 * @class Roo.bootstrap.TabPanel
14019 * @extends Roo.bootstrap.Component
14020 * Bootstrap TabPanel class
14021 * @cfg {Boolean} active panel active
14022 * @cfg {String} html panel content
14023 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14024 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14028 * Create a new TabPanel
14029 * @param {Object} config The config object
14032 Roo.bootstrap.TabPanel = function(config){
14033 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14037 * Fires when the active status changes
14038 * @param {Roo.bootstrap.TabPanel} this
14039 * @param {Boolean} state the new state
14044 * @event beforedeactivate
14045 * Fires before a tab is de-activated - can be used to do validation on a form.
14046 * @param {Roo.bootstrap.TabPanel} this
14047 * @return {Boolean} false if there is an error
14050 'beforedeactivate': true
14053 this.tabId = this.tabId || Roo.id();
14057 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14064 getAutoCreate : function(){
14067 // item is needed for carousel - not sure if it has any effect otherwise
14068 cls: 'tab-pane item',
14069 html: this.html || ''
14073 cfg.cls += ' active';
14077 cfg.tabId = this.tabId;
14084 initEvents: function()
14086 Roo.log('-------- init events on tab panel ---------');
14088 var p = this.parent();
14089 this.navId = this.navId || p.navId;
14091 if (typeof(this.navId) != 'undefined') {
14092 // not really needed.. but just in case.. parent should be a NavGroup.
14093 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14094 Roo.log(['register', tg, this]);
14100 onRender : function(ct, position)
14102 // Roo.log("Call onRender: " + this.xtype);
14104 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14112 setActive: function(state)
14114 Roo.log("panel - set active " + this.tabId + "=" + state);
14116 this.active = state;
14118 this.el.removeClass('active');
14120 } else if (!this.el.hasClass('active')) {
14121 this.el.addClass('active');
14123 this.fireEvent('changed', this, state);
14140 * @class Roo.bootstrap.DateField
14141 * @extends Roo.bootstrap.Input
14142 * Bootstrap DateField class
14143 * @cfg {Number} weekStart default 0
14144 * @cfg {Number} weekStart default 0
14145 * @cfg {Number} viewMode default empty, (months|years)
14146 * @cfg {Number} minViewMode default empty, (months|years)
14147 * @cfg {Number} startDate default -Infinity
14148 * @cfg {Number} endDate default Infinity
14149 * @cfg {Boolean} todayHighlight default false
14150 * @cfg {Boolean} todayBtn default false
14151 * @cfg {Boolean} calendarWeeks default false
14152 * @cfg {Object} daysOfWeekDisabled default empty
14154 * @cfg {Boolean} keyboardNavigation default true
14155 * @cfg {String} language default en
14158 * Create a new DateField
14159 * @param {Object} config The config object
14162 Roo.bootstrap.DateField = function(config){
14163 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14167 * Fires when this field show.
14168 * @param {Roo.bootstrap.DateField} this
14169 * @param {Mixed} date The date value
14174 * Fires when this field hide.
14175 * @param {Roo.bootstrap.DateField} this
14176 * @param {Mixed} date The date value
14181 * Fires when select a date.
14182 * @param {Roo.bootstrap.DateField} this
14183 * @param {Mixed} date The date value
14189 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14192 * @cfg {String} format
14193 * The default date format string which can be overriden for localization support. The format must be
14194 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14198 * @cfg {String} altFormats
14199 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14200 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14202 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14210 todayHighlight : false,
14216 keyboardNavigation: true,
14218 calendarWeeks: false,
14220 startDate: -Infinity,
14224 daysOfWeekDisabled: [],
14228 UTCDate: function()
14230 return new Date(Date.UTC.apply(Date, arguments));
14233 UTCToday: function()
14235 var today = new Date();
14236 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14239 getDate: function() {
14240 var d = this.getUTCDate();
14241 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14244 getUTCDate: function() {
14248 setDate: function(d) {
14249 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14252 setUTCDate: function(d) {
14254 this.setValue(this.formatDate(this.date));
14257 onRender: function(ct, position)
14260 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14262 this.language = this.language || 'en';
14263 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14264 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14266 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14267 this.format = this.format || 'm/d/y';
14268 this.isInline = false;
14269 this.isInput = true;
14270 this.component = this.el.select('.add-on', true).first() || false;
14271 this.component = (this.component && this.component.length === 0) ? false : this.component;
14272 this.hasInput = this.component && this.inputEL().length;
14274 if (typeof(this.minViewMode === 'string')) {
14275 switch (this.minViewMode) {
14277 this.minViewMode = 1;
14280 this.minViewMode = 2;
14283 this.minViewMode = 0;
14288 if (typeof(this.viewMode === 'string')) {
14289 switch (this.viewMode) {
14302 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14304 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14306 this.picker().on('mousedown', this.onMousedown, this);
14307 this.picker().on('click', this.onClick, this);
14309 this.picker().addClass('datepicker-dropdown');
14311 this.startViewMode = this.viewMode;
14314 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14315 if(!this.calendarWeeks){
14320 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14321 v.attr('colspan', function(i, val){
14322 return parseInt(val) + 1;
14327 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14329 this.setStartDate(this.startDate);
14330 this.setEndDate(this.endDate);
14332 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14339 if(this.isInline) {
14344 picker : function()
14346 return this.el.select('.datepicker', true).first();
14349 fillDow: function()
14351 var dowCnt = this.weekStart;
14360 if(this.calendarWeeks){
14368 while (dowCnt < this.weekStart + 7) {
14372 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14376 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14379 fillMonths: function()
14382 var months = this.picker().select('>.datepicker-months td', true).first();
14384 months.dom.innerHTML = '';
14390 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14393 months.createChild(month);
14401 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
14403 if (this.date < this.startDate) {
14404 this.viewDate = new Date(this.startDate);
14405 } else if (this.date > this.endDate) {
14406 this.viewDate = new Date(this.endDate);
14408 this.viewDate = new Date(this.date);
14416 var d = new Date(this.viewDate),
14417 year = d.getUTCFullYear(),
14418 month = d.getUTCMonth(),
14419 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14420 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14421 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14422 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14423 currentDate = this.date && this.date.valueOf(),
14424 today = this.UTCToday();
14426 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14428 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14430 // this.picker.select('>tfoot th.today').
14431 // .text(dates[this.language].today)
14432 // .toggle(this.todayBtn !== false);
14434 this.updateNavArrows();
14437 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14439 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14441 prevMonth.setUTCDate(day);
14443 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14445 var nextMonth = new Date(prevMonth);
14447 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14449 nextMonth = nextMonth.valueOf();
14451 var fillMonths = false;
14453 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14455 while(prevMonth.valueOf() < nextMonth) {
14458 if (prevMonth.getUTCDay() === this.weekStart) {
14460 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14468 if(this.calendarWeeks){
14469 // ISO 8601: First week contains first thursday.
14470 // ISO also states week starts on Monday, but we can be more abstract here.
14472 // Start of current week: based on weekstart/current date
14473 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14474 // Thursday of this week
14475 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14476 // First Thursday of year, year from thursday
14477 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14478 // Calendar week: ms between thursdays, div ms per day, div 7 days
14479 calWeek = (th - yth) / 864e5 / 7 + 1;
14481 fillMonths.cn.push({
14489 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14491 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14494 if (this.todayHighlight &&
14495 prevMonth.getUTCFullYear() == today.getFullYear() &&
14496 prevMonth.getUTCMonth() == today.getMonth() &&
14497 prevMonth.getUTCDate() == today.getDate()) {
14498 clsName += ' today';
14501 if (currentDate && prevMonth.valueOf() === currentDate) {
14502 clsName += ' active';
14505 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14506 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14507 clsName += ' disabled';
14510 fillMonths.cn.push({
14512 cls: 'day ' + clsName,
14513 html: prevMonth.getDate()
14516 prevMonth.setDate(prevMonth.getDate()+1);
14519 var currentYear = this.date && this.date.getUTCFullYear();
14520 var currentMonth = this.date && this.date.getUTCMonth();
14522 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14524 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14525 v.removeClass('active');
14527 if(currentYear === year && k === currentMonth){
14528 v.addClass('active');
14531 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14532 v.addClass('disabled');
14538 year = parseInt(year/10, 10) * 10;
14540 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14542 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14545 for (var i = -1; i < 11; i++) {
14546 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14548 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14556 showMode: function(dir)
14559 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14561 Roo.each(this.picker().select('>div',true).elements, function(v){
14562 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14565 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14570 if(this.isInline) return;
14572 this.picker().removeClass(['bottom', 'top']);
14574 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14576 * place to the top of element!
14580 this.picker().addClass('top');
14581 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14586 this.picker().addClass('bottom');
14588 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14591 parseDate : function(value)
14593 if(!value || value instanceof Date){
14596 var v = Date.parseDate(value, this.format);
14597 if (!v && this.useIso) {
14598 v = Date.parseDate(value, 'Y-m-d');
14600 if(!v && this.altFormats){
14601 if(!this.altFormatsArray){
14602 this.altFormatsArray = this.altFormats.split("|");
14604 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14605 v = Date.parseDate(value, this.altFormatsArray[i]);
14611 formatDate : function(date, fmt)
14613 return (!date || !(date instanceof Date)) ?
14614 date : date.dateFormat(fmt || this.format);
14617 onFocus : function()
14619 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14623 onBlur : function()
14625 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14627 var d = this.inputEl().getValue();
14638 this.picker().show();
14642 this.fireEvent('show', this, this.date);
14647 if(this.isInline) return;
14648 this.picker().hide();
14649 this.viewMode = this.startViewMode;
14652 this.fireEvent('hide', this, this.date);
14656 onMousedown: function(e)
14658 e.stopPropagation();
14659 e.preventDefault();
14664 Roo.bootstrap.DateField.superclass.keyup.call(this);
14668 setValue: function(v)
14670 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14672 var d = new Date(v);
14674 if(isNaN(d.getTime())){
14678 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14682 this.fireEvent('select', this, this.date);
14686 getValue: function()
14688 return this.formatDate(this.date);
14691 fireKey: function(e)
14693 if (!this.picker().isVisible()){
14694 if (e.keyCode == 27) // allow escape to hide and re-show picker
14699 var dateChanged = false,
14701 newDate, newViewDate;
14706 e.preventDefault();
14710 if (!this.keyboardNavigation) break;
14711 dir = e.keyCode == 37 ? -1 : 1;
14714 newDate = this.moveYear(this.date, dir);
14715 newViewDate = this.moveYear(this.viewDate, dir);
14716 } else if (e.shiftKey){
14717 newDate = this.moveMonth(this.date, dir);
14718 newViewDate = this.moveMonth(this.viewDate, dir);
14720 newDate = new Date(this.date);
14721 newDate.setUTCDate(this.date.getUTCDate() + dir);
14722 newViewDate = new Date(this.viewDate);
14723 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14725 if (this.dateWithinRange(newDate)){
14726 this.date = newDate;
14727 this.viewDate = newViewDate;
14728 this.setValue(this.formatDate(this.date));
14730 e.preventDefault();
14731 dateChanged = true;
14736 if (!this.keyboardNavigation) break;
14737 dir = e.keyCode == 38 ? -1 : 1;
14739 newDate = this.moveYear(this.date, dir);
14740 newViewDate = this.moveYear(this.viewDate, dir);
14741 } else if (e.shiftKey){
14742 newDate = this.moveMonth(this.date, dir);
14743 newViewDate = this.moveMonth(this.viewDate, dir);
14745 newDate = new Date(this.date);
14746 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14747 newViewDate = new Date(this.viewDate);
14748 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14750 if (this.dateWithinRange(newDate)){
14751 this.date = newDate;
14752 this.viewDate = newViewDate;
14753 this.setValue(this.formatDate(this.date));
14755 e.preventDefault();
14756 dateChanged = true;
14760 this.setValue(this.formatDate(this.date));
14762 e.preventDefault();
14765 this.setValue(this.formatDate(this.date));
14779 onClick: function(e)
14781 e.stopPropagation();
14782 e.preventDefault();
14784 var target = e.getTarget();
14786 if(target.nodeName.toLowerCase() === 'i'){
14787 target = Roo.get(target).dom.parentNode;
14790 var nodeName = target.nodeName;
14791 var className = target.className;
14792 var html = target.innerHTML;
14794 switch(nodeName.toLowerCase()) {
14796 switch(className) {
14802 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14803 switch(this.viewMode){
14805 this.viewDate = this.moveMonth(this.viewDate, dir);
14809 this.viewDate = this.moveYear(this.viewDate, dir);
14815 var date = new Date();
14816 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14818 this.setValue(this.formatDate(this.date));
14825 if (className.indexOf('disabled') === -1) {
14826 this.viewDate.setUTCDate(1);
14827 if (className.indexOf('month') !== -1) {
14828 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14830 var year = parseInt(html, 10) || 0;
14831 this.viewDate.setUTCFullYear(year);
14840 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
14841 var day = parseInt(html, 10) || 1;
14842 var year = this.viewDate.getUTCFullYear(),
14843 month = this.viewDate.getUTCMonth();
14845 if (className.indexOf('old') !== -1) {
14852 } else if (className.indexOf('new') !== -1) {
14860 this.date = this.UTCDate(year, month, day,0,0,0,0);
14861 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
14863 this.setValue(this.formatDate(this.date));
14870 setStartDate: function(startDate)
14872 this.startDate = startDate || -Infinity;
14873 if (this.startDate !== -Infinity) {
14874 this.startDate = this.parseDate(this.startDate);
14877 this.updateNavArrows();
14880 setEndDate: function(endDate)
14882 this.endDate = endDate || Infinity;
14883 if (this.endDate !== Infinity) {
14884 this.endDate = this.parseDate(this.endDate);
14887 this.updateNavArrows();
14890 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
14892 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
14893 if (typeof(this.daysOfWeekDisabled) !== 'object') {
14894 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
14896 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
14897 return parseInt(d, 10);
14900 this.updateNavArrows();
14903 updateNavArrows: function()
14905 var d = new Date(this.viewDate),
14906 year = d.getUTCFullYear(),
14907 month = d.getUTCMonth();
14909 Roo.each(this.picker().select('.prev', true).elements, function(v){
14911 switch (this.viewMode) {
14914 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
14920 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
14927 Roo.each(this.picker().select('.next', true).elements, function(v){
14929 switch (this.viewMode) {
14932 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
14938 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
14946 moveMonth: function(date, dir)
14948 if (!dir) return date;
14949 var new_date = new Date(date.valueOf()),
14950 day = new_date.getUTCDate(),
14951 month = new_date.getUTCMonth(),
14952 mag = Math.abs(dir),
14954 dir = dir > 0 ? 1 : -1;
14957 // If going back one month, make sure month is not current month
14958 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
14960 return new_date.getUTCMonth() == month;
14962 // If going forward one month, make sure month is as expected
14963 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
14965 return new_date.getUTCMonth() != new_month;
14967 new_month = month + dir;
14968 new_date.setUTCMonth(new_month);
14969 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
14970 if (new_month < 0 || new_month > 11)
14971 new_month = (new_month + 12) % 12;
14973 // For magnitudes >1, move one month at a time...
14974 for (var i=0; i<mag; i++)
14975 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
14976 new_date = this.moveMonth(new_date, dir);
14977 // ...then reset the day, keeping it in the new month
14978 new_month = new_date.getUTCMonth();
14979 new_date.setUTCDate(day);
14981 return new_month != new_date.getUTCMonth();
14984 // Common date-resetting loop -- if date is beyond end of month, make it
14987 new_date.setUTCDate(--day);
14988 new_date.setUTCMonth(new_month);
14993 moveYear: function(date, dir)
14995 return this.moveMonth(date, dir*12);
14998 dateWithinRange: function(date)
15000 return date >= this.startDate && date <= this.endDate;
15006 this.picker().remove();
15011 Roo.apply(Roo.bootstrap.DateField, {
15022 html: '<i class="fa fa-arrow-left"/>'
15032 html: '<i class="fa fa-arrow-right"/>'
15074 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15075 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15076 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15077 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15078 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15091 navFnc: 'FullYear',
15096 navFnc: 'FullYear',
15101 Roo.apply(Roo.bootstrap.DateField, {
15105 cls: 'datepicker dropdown-menu',
15109 cls: 'datepicker-days',
15113 cls: 'table-condensed',
15115 Roo.bootstrap.DateField.head,
15119 Roo.bootstrap.DateField.footer
15126 cls: 'datepicker-months',
15130 cls: 'table-condensed',
15132 Roo.bootstrap.DateField.head,
15133 Roo.bootstrap.DateField.content,
15134 Roo.bootstrap.DateField.footer
15141 cls: 'datepicker-years',
15145 cls: 'table-condensed',
15147 Roo.bootstrap.DateField.head,
15148 Roo.bootstrap.DateField.content,
15149 Roo.bootstrap.DateField.footer
15168 * @class Roo.bootstrap.TimeField
15169 * @extends Roo.bootstrap.Input
15170 * Bootstrap DateField class
15174 * Create a new TimeField
15175 * @param {Object} config The config object
15178 Roo.bootstrap.TimeField = function(config){
15179 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15183 * Fires when this field show.
15184 * @param {Roo.bootstrap.DateField} this
15185 * @param {Mixed} date The date value
15190 * Fires when this field hide.
15191 * @param {Roo.bootstrap.DateField} this
15192 * @param {Mixed} date The date value
15197 * Fires when select a date.
15198 * @param {Roo.bootstrap.DateField} this
15199 * @param {Mixed} date The date value
15205 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15208 * @cfg {String} format
15209 * The default time format string which can be overriden for localization support. The format must be
15210 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15214 onRender: function(ct, position)
15217 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15219 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15221 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15223 this.pop = this.picker().select('>.datepicker-time',true).first();
15224 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15226 this.picker().on('mousedown', this.onMousedown, this);
15227 this.picker().on('click', this.onClick, this);
15229 this.picker().addClass('datepicker-dropdown');
15234 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15235 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15236 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15237 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15238 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15239 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15243 fireKey: function(e){
15244 if (!this.picker().isVisible()){
15245 if (e.keyCode == 27) // allow escape to hide and re-show picker
15250 e.preventDefault();
15258 this.onTogglePeriod();
15261 this.onIncrementMinutes();
15264 this.onDecrementMinutes();
15273 onClick: function(e) {
15274 e.stopPropagation();
15275 e.preventDefault();
15278 picker : function()
15280 return this.el.select('.datepicker', true).first();
15283 fillTime: function()
15285 var time = this.pop.select('tbody', true).first();
15287 time.dom.innerHTML = '';
15302 cls: 'hours-up glyphicon glyphicon-chevron-up'
15322 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15343 cls: 'timepicker-hour',
15358 cls: 'timepicker-minute',
15373 cls: 'btn btn-primary period',
15395 cls: 'hours-down glyphicon glyphicon-chevron-down'
15415 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15433 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15440 var hours = this.time.getHours();
15441 var minutes = this.time.getMinutes();
15454 hours = hours - 12;
15458 hours = '0' + hours;
15462 minutes = '0' + minutes;
15465 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15466 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15467 this.pop.select('button', true).first().dom.innerHTML = period;
15473 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15475 var cls = ['bottom'];
15477 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15484 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15489 this.picker().addClass(cls.join('-'));
15493 Roo.each(cls, function(c){
15495 _this.picker().setTop(_this.inputEl().getHeight());
15499 _this.picker().setTop(0 - _this.picker().getHeight());
15504 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15508 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15515 onFocus : function()
15517 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15521 onBlur : function()
15523 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15529 this.picker().show();
15534 this.fireEvent('show', this, this.date);
15539 this.picker().hide();
15542 this.fireEvent('hide', this, this.date);
15545 setTime : function()
15548 this.setValue(this.time.format(this.format));
15550 this.fireEvent('select', this, this.date);
15555 onMousedown: function(e){
15556 e.stopPropagation();
15557 e.preventDefault();
15560 onIncrementHours: function()
15562 Roo.log('onIncrementHours');
15563 this.time = this.time.add(Date.HOUR, 1);
15568 onDecrementHours: function()
15570 Roo.log('onDecrementHours');
15571 this.time = this.time.add(Date.HOUR, -1);
15575 onIncrementMinutes: function()
15577 Roo.log('onIncrementMinutes');
15578 this.time = this.time.add(Date.MINUTE, 1);
15582 onDecrementMinutes: function()
15584 Roo.log('onDecrementMinutes');
15585 this.time = this.time.add(Date.MINUTE, -1);
15589 onTogglePeriod: function()
15591 Roo.log('onTogglePeriod');
15592 this.time = this.time.add(Date.HOUR, 12);
15599 Roo.apply(Roo.bootstrap.TimeField, {
15629 cls: 'btn btn-info ok',
15641 Roo.apply(Roo.bootstrap.TimeField, {
15645 cls: 'datepicker dropdown-menu',
15649 cls: 'datepicker-time',
15653 cls: 'table-condensed',
15655 Roo.bootstrap.TimeField.content,
15656 Roo.bootstrap.TimeField.footer
15675 * @class Roo.bootstrap.CheckBox
15676 * @extends Roo.bootstrap.Input
15677 * Bootstrap CheckBox class
15679 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15680 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15681 * @cfg {String} boxLabel The text that appears beside the checkbox
15682 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15683 * @cfg {Boolean} checked initnal the element
15687 * Create a new CheckBox
15688 * @param {Object} config The config object
15691 Roo.bootstrap.CheckBox = function(config){
15692 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15697 * Fires when the element is checked or unchecked.
15698 * @param {Roo.bootstrap.CheckBox} this This input
15699 * @param {Boolean} checked The new checked value
15705 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15707 inputType: 'checkbox',
15714 getAutoCreate : function()
15716 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15722 cfg.cls = 'form-group checkbox' //input-group
15730 type : this.inputType,
15731 value : (!this.checked) ? this.valueOff : this.inputValue,
15732 cls : 'roo-checkbox', //'form-box',
15733 placeholder : this.placeholder || ''
15737 if (this.weight) { // Validity check?
15738 cfg.cls += " checkbox-" + this.weight;
15741 if (this.disabled) {
15742 input.disabled=true;
15746 input.checked = this.checked;
15750 input.name = this.name;
15754 input.cls += ' input-' + this.size;
15758 ['xs','sm','md','lg'].map(function(size){
15759 if (settings[size]) {
15760 cfg.cls += ' col-' + size + '-' + settings[size];
15766 var inputblock = input;
15771 if (this.before || this.after) {
15774 cls : 'input-group',
15778 inputblock.cn.push({
15780 cls : 'input-group-addon',
15784 inputblock.cn.push(input);
15786 inputblock.cn.push({
15788 cls : 'input-group-addon',
15795 if (align ==='left' && this.fieldLabel.length) {
15796 Roo.log("left and has label");
15802 cls : 'control-label col-md-' + this.labelWidth,
15803 html : this.fieldLabel
15807 cls : "col-md-" + (12 - this.labelWidth),
15814 } else if ( this.fieldLabel.length) {
15819 tag: this.boxLabel ? 'span' : 'label',
15821 cls: 'control-label box-input-label',
15822 //cls : 'input-group-addon',
15823 html : this.fieldLabel
15833 Roo.log(" no label && no align");
15834 cfg.cn = [ inputblock ] ;
15843 html: this.boxLabel
15855 * return the real input element.
15857 inputEl: function ()
15859 return this.el.select('input.roo-checkbox',true).first();
15864 return this.el.select('label.control-label',true).first();
15867 initEvents : function()
15869 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
15871 this.inputEl().on('click', this.onClick, this);
15875 onClick : function()
15877 this.setChecked(!this.checked);
15880 setChecked : function(state,suppressEvent)
15882 this.checked = state;
15884 this.inputEl().dom.checked = state;
15886 if(suppressEvent !== true){
15887 this.fireEvent('check', this, state);
15890 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15894 setValue : function(v,suppressEvent)
15896 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
15910 * @class Roo.bootstrap.Radio
15911 * @extends Roo.bootstrap.CheckBox
15912 * Bootstrap Radio class
15915 * Create a new Radio
15916 * @param {Object} config The config object
15919 Roo.bootstrap.Radio = function(config){
15920 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
15924 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
15926 inputType: 'radio',
15930 getAutoCreate : function()
15932 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15938 cfg.cls = 'form-group radio' //input-group
15943 type : this.inputType,
15944 value : (!this.checked) ? this.valueOff : this.inputValue,
15946 placeholder : this.placeholder || ''
15949 if (this.weight) { // Validity check?
15950 cfg.cls += " radio-" + this.weight;
15952 if (this.disabled) {
15953 input.disabled=true;
15957 input.checked = this.checked;
15961 input.name = this.name;
15965 input.cls += ' input-' + this.size;
15969 ['xs','sm','md','lg'].map(function(size){
15970 if (settings[size]) {
15971 cfg.cls += ' col-' + size + '-' + settings[size];
15975 var inputblock = input;
15977 if (this.before || this.after) {
15980 cls : 'input-group',
15984 inputblock.cn.push({
15986 cls : 'input-group-addon',
15990 inputblock.cn.push(input);
15992 inputblock.cn.push({
15994 cls : 'input-group-addon',
16001 if (align ==='left' && this.fieldLabel.length) {
16002 Roo.log("left and has label");
16008 cls : 'control-label col-md-' + this.labelWidth,
16009 html : this.fieldLabel
16013 cls : "col-md-" + (12 - this.labelWidth),
16020 } else if ( this.fieldLabel.length) {
16027 cls: 'control-label box-input-label',
16028 //cls : 'input-group-addon',
16029 html : this.fieldLabel
16039 Roo.log(" no label && no align");
16054 html: this.boxLabel
16061 inputEl: function ()
16063 return this.el.select('input.roo-radio',true).first();
16065 onClick : function()
16067 this.setChecked(true);
16070 setChecked : function(state,suppressEvent)
16073 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16074 v.dom.checked = false;
16078 this.checked = state;
16079 this.inputEl().dom.checked = state;
16081 if(suppressEvent !== true){
16082 this.fireEvent('check', this, state);
16085 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16089 getGroupValue : function()
16092 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16093 if(v.dom.checked == true){
16094 value = v.dom.value;
16102 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16103 * @return {Mixed} value The field value
16105 getValue : function(){
16106 return this.getGroupValue();
16112 //<script type="text/javascript">
16115 * Based Ext JS Library 1.1.1
16116 * Copyright(c) 2006-2007, Ext JS, LLC.
16122 * @class Roo.HtmlEditorCore
16123 * @extends Roo.Component
16124 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16126 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16129 Roo.HtmlEditorCore = function(config){
16132 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16135 * @event initialize
16136 * Fires when the editor is fully initialized (including the iframe)
16137 * @param {Roo.HtmlEditorCore} this
16142 * Fires when the editor is first receives the focus. Any insertion must wait
16143 * until after this event.
16144 * @param {Roo.HtmlEditorCore} this
16148 * @event beforesync
16149 * Fires before the textarea is updated with content from the editor iframe. Return false
16150 * to cancel the sync.
16151 * @param {Roo.HtmlEditorCore} this
16152 * @param {String} html
16156 * @event beforepush
16157 * Fires before the iframe editor is updated with content from the textarea. Return false
16158 * to cancel the push.
16159 * @param {Roo.HtmlEditorCore} this
16160 * @param {String} html
16165 * Fires when the textarea is updated with content from the editor iframe.
16166 * @param {Roo.HtmlEditorCore} this
16167 * @param {String} html
16172 * Fires when the iframe editor is updated with content from the textarea.
16173 * @param {Roo.HtmlEditorCore} this
16174 * @param {String} html
16179 * @event editorevent
16180 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16181 * @param {Roo.HtmlEditorCore} this
16189 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16193 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16199 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16204 * @cfg {Number} height (in pixels)
16208 * @cfg {Number} width (in pixels)
16213 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16216 stylesheets: false,
16221 // private properties
16222 validationEvent : false,
16224 initialized : false,
16226 sourceEditMode : false,
16227 onFocus : Roo.emptyFn,
16229 hideMode:'offsets',
16237 * Protected method that will not generally be called directly. It
16238 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16239 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16241 getDocMarkup : function(){
16244 Roo.log(this.stylesheets);
16246 // inherit styels from page...??
16247 if (this.stylesheets === false) {
16249 Roo.get(document.head).select('style').each(function(node) {
16250 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16253 Roo.get(document.head).select('link').each(function(node) {
16254 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16257 } else if (!this.stylesheets.length) {
16259 st = '<style type="text/css">' +
16260 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16263 Roo.each(this.stylesheets, function(s) {
16264 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16269 st += '<style type="text/css">' +
16270 'IMG { cursor: pointer } ' +
16274 return '<html><head>' + st +
16275 //<style type="text/css">' +
16276 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16278 ' </head><body class="roo-htmleditor-body"></body></html>';
16282 onRender : function(ct, position)
16285 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16286 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16289 this.el.dom.style.border = '0 none';
16290 this.el.dom.setAttribute('tabIndex', -1);
16291 this.el.addClass('x-hidden hide');
16295 if(Roo.isIE){ // fix IE 1px bogus margin
16296 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16300 this.frameId = Roo.id();
16304 var iframe = this.owner.wrap.createChild({
16306 cls: 'form-control', // bootstrap..
16308 name: this.frameId,
16309 frameBorder : 'no',
16310 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16315 this.iframe = iframe.dom;
16317 this.assignDocWin();
16319 this.doc.designMode = 'on';
16322 this.doc.write(this.getDocMarkup());
16326 var task = { // must defer to wait for browser to be ready
16328 //console.log("run task?" + this.doc.readyState);
16329 this.assignDocWin();
16330 if(this.doc.body || this.doc.readyState == 'complete'){
16332 this.doc.designMode="on";
16336 Roo.TaskMgr.stop(task);
16337 this.initEditor.defer(10, this);
16344 Roo.TaskMgr.start(task);
16351 onResize : function(w, h)
16353 Roo.log('resize: ' +w + ',' + h );
16354 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16358 if(typeof w == 'number'){
16360 this.iframe.style.width = w + 'px';
16362 if(typeof h == 'number'){
16364 this.iframe.style.height = h + 'px';
16366 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16373 * Toggles the editor between standard and source edit mode.
16374 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16376 toggleSourceEdit : function(sourceEditMode){
16378 this.sourceEditMode = sourceEditMode === true;
16380 if(this.sourceEditMode){
16382 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16385 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16386 //this.iframe.className = '';
16389 //this.setSize(this.owner.wrap.getSize());
16390 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16397 * Protected method that will not generally be called directly. If you need/want
16398 * custom HTML cleanup, this is the method you should override.
16399 * @param {String} html The HTML to be cleaned
16400 * return {String} The cleaned HTML
16402 cleanHtml : function(html){
16403 html = String(html);
16404 if(html.length > 5){
16405 if(Roo.isSafari){ // strip safari nonsense
16406 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16409 if(html == ' '){
16416 * HTML Editor -> Textarea
16417 * Protected method that will not generally be called directly. Syncs the contents
16418 * of the editor iframe with the textarea.
16420 syncValue : function(){
16421 if(this.initialized){
16422 var bd = (this.doc.body || this.doc.documentElement);
16423 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16424 var html = bd.innerHTML;
16426 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16427 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16429 html = '<div style="'+m[0]+'">' + html + '</div>';
16432 html = this.cleanHtml(html);
16433 // fix up the special chars.. normaly like back quotes in word...
16434 // however we do not want to do this with chinese..
16435 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16436 var cc = b.charCodeAt();
16438 (cc >= 0x4E00 && cc < 0xA000 ) ||
16439 (cc >= 0x3400 && cc < 0x4E00 ) ||
16440 (cc >= 0xf900 && cc < 0xfb00 )
16446 if(this.owner.fireEvent('beforesync', this, html) !== false){
16447 this.el.dom.value = html;
16448 this.owner.fireEvent('sync', this, html);
16454 * Protected method that will not generally be called directly. Pushes the value of the textarea
16455 * into the iframe editor.
16457 pushValue : function(){
16458 if(this.initialized){
16459 var v = this.el.dom.value.trim();
16461 // if(v.length < 1){
16465 if(this.owner.fireEvent('beforepush', this, v) !== false){
16466 var d = (this.doc.body || this.doc.documentElement);
16468 this.cleanUpPaste();
16469 this.el.dom.value = d.innerHTML;
16470 this.owner.fireEvent('push', this, v);
16476 deferFocus : function(){
16477 this.focus.defer(10, this);
16481 focus : function(){
16482 if(this.win && !this.sourceEditMode){
16489 assignDocWin: function()
16491 var iframe = this.iframe;
16494 this.doc = iframe.contentWindow.document;
16495 this.win = iframe.contentWindow;
16497 if (!Roo.get(this.frameId)) {
16500 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16501 this.win = Roo.get(this.frameId).dom.contentWindow;
16506 initEditor : function(){
16507 //console.log("INIT EDITOR");
16508 this.assignDocWin();
16512 this.doc.designMode="on";
16514 this.doc.write(this.getDocMarkup());
16517 var dbody = (this.doc.body || this.doc.documentElement);
16518 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16519 // this copies styles from the containing element into thsi one..
16520 // not sure why we need all of this..
16521 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16523 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16524 //ss['background-attachment'] = 'fixed'; // w3c
16525 dbody.bgProperties = 'fixed'; // ie
16526 //Roo.DomHelper.applyStyles(dbody, ss);
16527 Roo.EventManager.on(this.doc, {
16528 //'mousedown': this.onEditorEvent,
16529 'mouseup': this.onEditorEvent,
16530 'dblclick': this.onEditorEvent,
16531 'click': this.onEditorEvent,
16532 'keyup': this.onEditorEvent,
16537 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16539 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16540 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16542 this.initialized = true;
16544 this.owner.fireEvent('initialize', this);
16549 onDestroy : function(){
16555 //for (var i =0; i < this.toolbars.length;i++) {
16556 // // fixme - ask toolbars for heights?
16557 // this.toolbars[i].onDestroy();
16560 //this.wrap.dom.innerHTML = '';
16561 //this.wrap.remove();
16566 onFirstFocus : function(){
16568 this.assignDocWin();
16571 this.activated = true;
16574 if(Roo.isGecko){ // prevent silly gecko errors
16576 var s = this.win.getSelection();
16577 if(!s.focusNode || s.focusNode.nodeType != 3){
16578 var r = s.getRangeAt(0);
16579 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16584 this.execCmd('useCSS', true);
16585 this.execCmd('styleWithCSS', false);
16588 this.owner.fireEvent('activate', this);
16592 adjustFont: function(btn){
16593 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16594 //if(Roo.isSafari){ // safari
16597 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16598 if(Roo.isSafari){ // safari
16599 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16600 v = (v < 10) ? 10 : v;
16601 v = (v > 48) ? 48 : v;
16602 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16607 v = Math.max(1, v+adjust);
16609 this.execCmd('FontSize', v );
16612 onEditorEvent : function(e){
16613 this.owner.fireEvent('editorevent', this, e);
16614 // this.updateToolbar();
16615 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16618 insertTag : function(tg)
16620 // could be a bit smarter... -> wrap the current selected tRoo..
16621 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16623 range = this.createRange(this.getSelection());
16624 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16625 wrappingNode.appendChild(range.extractContents());
16626 range.insertNode(wrappingNode);
16633 this.execCmd("formatblock", tg);
16637 insertText : function(txt)
16641 var range = this.createRange();
16642 range.deleteContents();
16643 //alert(Sender.getAttribute('label'));
16645 range.insertNode(this.doc.createTextNode(txt));
16651 * Executes a Midas editor command on the editor document and performs necessary focus and
16652 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16653 * @param {String} cmd The Midas command
16654 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16656 relayCmd : function(cmd, value){
16658 this.execCmd(cmd, value);
16659 this.owner.fireEvent('editorevent', this);
16660 //this.updateToolbar();
16661 this.owner.deferFocus();
16665 * Executes a Midas editor command directly on the editor document.
16666 * For visual commands, you should use {@link #relayCmd} instead.
16667 * <b>This should only be called after the editor is initialized.</b>
16668 * @param {String} cmd The Midas command
16669 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16671 execCmd : function(cmd, value){
16672 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16679 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16681 * @param {String} text | dom node..
16683 insertAtCursor : function(text)
16688 if(!this.activated){
16694 var r = this.doc.selection.createRange();
16705 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16709 // from jquery ui (MIT licenced)
16711 var win = this.win;
16713 if (win.getSelection && win.getSelection().getRangeAt) {
16714 range = win.getSelection().getRangeAt(0);
16715 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16716 range.insertNode(node);
16717 } else if (win.document.selection && win.document.selection.createRange) {
16718 // no firefox support
16719 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16720 win.document.selection.createRange().pasteHTML(txt);
16722 // no firefox support
16723 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16724 this.execCmd('InsertHTML', txt);
16733 mozKeyPress : function(e){
16735 var c = e.getCharCode(), cmd;
16738 c = String.fromCharCode(c).toLowerCase();
16752 this.cleanUpPaste.defer(100, this);
16760 e.preventDefault();
16768 fixKeys : function(){ // load time branching for fastest keydown performance
16770 return function(e){
16771 var k = e.getKey(), r;
16774 r = this.doc.selection.createRange();
16777 r.pasteHTML('    ');
16784 r = this.doc.selection.createRange();
16786 var target = r.parentElement();
16787 if(!target || target.tagName.toLowerCase() != 'li'){
16789 r.pasteHTML('<br />');
16795 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16796 this.cleanUpPaste.defer(100, this);
16802 }else if(Roo.isOpera){
16803 return function(e){
16804 var k = e.getKey();
16808 this.execCmd('InsertHTML','    ');
16811 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16812 this.cleanUpPaste.defer(100, this);
16817 }else if(Roo.isSafari){
16818 return function(e){
16819 var k = e.getKey();
16823 this.execCmd('InsertText','\t');
16827 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16828 this.cleanUpPaste.defer(100, this);
16836 getAllAncestors: function()
16838 var p = this.getSelectedNode();
16841 a.push(p); // push blank onto stack..
16842 p = this.getParentElement();
16846 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
16850 a.push(this.doc.body);
16854 lastSelNode : false,
16857 getSelection : function()
16859 this.assignDocWin();
16860 return Roo.isIE ? this.doc.selection : this.win.getSelection();
16863 getSelectedNode: function()
16865 // this may only work on Gecko!!!
16867 // should we cache this!!!!
16872 var range = this.createRange(this.getSelection()).cloneRange();
16875 var parent = range.parentElement();
16877 var testRange = range.duplicate();
16878 testRange.moveToElementText(parent);
16879 if (testRange.inRange(range)) {
16882 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
16885 parent = parent.parentElement;
16890 // is ancestor a text element.
16891 var ac = range.commonAncestorContainer;
16892 if (ac.nodeType == 3) {
16893 ac = ac.parentNode;
16896 var ar = ac.childNodes;
16899 var other_nodes = [];
16900 var has_other_nodes = false;
16901 for (var i=0;i<ar.length;i++) {
16902 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
16905 // fullly contained node.
16907 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
16912 // probably selected..
16913 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
16914 other_nodes.push(ar[i]);
16918 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
16923 has_other_nodes = true;
16925 if (!nodes.length && other_nodes.length) {
16926 nodes= other_nodes;
16928 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
16934 createRange: function(sel)
16936 // this has strange effects when using with
16937 // top toolbar - not sure if it's a great idea.
16938 //this.editor.contentWindow.focus();
16939 if (typeof sel != "undefined") {
16941 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
16943 return this.doc.createRange();
16946 return this.doc.createRange();
16949 getParentElement: function()
16952 this.assignDocWin();
16953 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
16955 var range = this.createRange(sel);
16958 var p = range.commonAncestorContainer;
16959 while (p.nodeType == 3) { // text node
16970 * Range intersection.. the hard stuff...
16974 * [ -- selected range --- ]
16978 * if end is before start or hits it. fail.
16979 * if start is after end or hits it fail.
16981 * if either hits (but other is outside. - then it's not
16987 // @see http://www.thismuchiknow.co.uk/?p=64.
16988 rangeIntersectsNode : function(range, node)
16990 var nodeRange = node.ownerDocument.createRange();
16992 nodeRange.selectNode(node);
16994 nodeRange.selectNodeContents(node);
16997 var rangeStartRange = range.cloneRange();
16998 rangeStartRange.collapse(true);
17000 var rangeEndRange = range.cloneRange();
17001 rangeEndRange.collapse(false);
17003 var nodeStartRange = nodeRange.cloneRange();
17004 nodeStartRange.collapse(true);
17006 var nodeEndRange = nodeRange.cloneRange();
17007 nodeEndRange.collapse(false);
17009 return rangeStartRange.compareBoundaryPoints(
17010 Range.START_TO_START, nodeEndRange) == -1 &&
17011 rangeEndRange.compareBoundaryPoints(
17012 Range.START_TO_START, nodeStartRange) == 1;
17016 rangeCompareNode : function(range, node)
17018 var nodeRange = node.ownerDocument.createRange();
17020 nodeRange.selectNode(node);
17022 nodeRange.selectNodeContents(node);
17026 range.collapse(true);
17028 nodeRange.collapse(true);
17030 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17031 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17033 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17035 var nodeIsBefore = ss == 1;
17036 var nodeIsAfter = ee == -1;
17038 if (nodeIsBefore && nodeIsAfter)
17040 if (!nodeIsBefore && nodeIsAfter)
17041 return 1; //right trailed.
17043 if (nodeIsBefore && !nodeIsAfter)
17044 return 2; // left trailed.
17049 // private? - in a new class?
17050 cleanUpPaste : function()
17052 // cleans up the whole document..
17053 Roo.log('cleanuppaste');
17055 this.cleanUpChildren(this.doc.body);
17056 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17057 if (clean != this.doc.body.innerHTML) {
17058 this.doc.body.innerHTML = clean;
17063 cleanWordChars : function(input) {// change the chars to hex code
17064 var he = Roo.HtmlEditorCore;
17066 var output = input;
17067 Roo.each(he.swapCodes, function(sw) {
17068 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17070 output = output.replace(swapper, sw[1]);
17077 cleanUpChildren : function (n)
17079 if (!n.childNodes.length) {
17082 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17083 this.cleanUpChild(n.childNodes[i]);
17090 cleanUpChild : function (node)
17093 //console.log(node);
17094 if (node.nodeName == "#text") {
17095 // clean up silly Windows -- stuff?
17098 if (node.nodeName == "#comment") {
17099 node.parentNode.removeChild(node);
17100 // clean up silly Windows -- stuff?
17104 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
17106 node.parentNode.removeChild(node);
17111 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17113 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17114 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17116 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17117 // remove_keep_children = true;
17120 if (remove_keep_children) {
17121 this.cleanUpChildren(node);
17122 // inserts everything just before this node...
17123 while (node.childNodes.length) {
17124 var cn = node.childNodes[0];
17125 node.removeChild(cn);
17126 node.parentNode.insertBefore(cn, node);
17128 node.parentNode.removeChild(node);
17132 if (!node.attributes || !node.attributes.length) {
17133 this.cleanUpChildren(node);
17137 function cleanAttr(n,v)
17140 if (v.match(/^\./) || v.match(/^\//)) {
17143 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17146 if (v.match(/^#/)) {
17149 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17150 node.removeAttribute(n);
17154 function cleanStyle(n,v)
17156 if (v.match(/expression/)) { //XSS?? should we even bother..
17157 node.removeAttribute(n);
17160 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
17161 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
17164 var parts = v.split(/;/);
17167 Roo.each(parts, function(p) {
17168 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17172 var l = p.split(':').shift().replace(/\s+/g,'');
17173 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17175 if ( cblack.indexOf(l) > -1) {
17176 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17177 //node.removeAttribute(n);
17181 // only allow 'c whitelisted system attributes'
17182 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17183 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17184 //node.removeAttribute(n);
17194 if (clean.length) {
17195 node.setAttribute(n, clean.join(';'));
17197 node.removeAttribute(n);
17203 for (var i = node.attributes.length-1; i > -1 ; i--) {
17204 var a = node.attributes[i];
17207 if (a.name.toLowerCase().substr(0,2)=='on') {
17208 node.removeAttribute(a.name);
17211 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17212 node.removeAttribute(a.name);
17215 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17216 cleanAttr(a.name,a.value); // fixme..
17219 if (a.name == 'style') {
17220 cleanStyle(a.name,a.value);
17223 /// clean up MS crap..
17224 // tecnically this should be a list of valid class'es..
17227 if (a.name == 'class') {
17228 if (a.value.match(/^Mso/)) {
17229 node.className = '';
17232 if (a.value.match(/body/)) {
17233 node.className = '';
17244 this.cleanUpChildren(node);
17249 * Clean up MS wordisms...
17251 cleanWord : function(node)
17254 var cleanWordChildren = function()
17256 if (!node.childNodes.length) {
17259 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17260 _t.cleanWord(node.childNodes[i]);
17266 this.cleanWord(this.doc.body);
17269 if (node.nodeName == "#text") {
17270 // clean up silly Windows -- stuff?
17273 if (node.nodeName == "#comment") {
17274 node.parentNode.removeChild(node);
17275 // clean up silly Windows -- stuff?
17279 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17280 node.parentNode.removeChild(node);
17284 // remove - but keep children..
17285 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17286 while (node.childNodes.length) {
17287 var cn = node.childNodes[0];
17288 node.removeChild(cn);
17289 node.parentNode.insertBefore(cn, node);
17291 node.parentNode.removeChild(node);
17292 cleanWordChildren();
17296 if (node.className.length) {
17298 var cn = node.className.split(/\W+/);
17300 Roo.each(cn, function(cls) {
17301 if (cls.match(/Mso[a-zA-Z]+/)) {
17306 node.className = cna.length ? cna.join(' ') : '';
17308 node.removeAttribute("class");
17312 if (node.hasAttribute("lang")) {
17313 node.removeAttribute("lang");
17316 if (node.hasAttribute("style")) {
17318 var styles = node.getAttribute("style").split(";");
17320 Roo.each(styles, function(s) {
17321 if (!s.match(/:/)) {
17324 var kv = s.split(":");
17325 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17328 // what ever is left... we allow.
17331 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17332 if (!nstyle.length) {
17333 node.removeAttribute('style');
17337 cleanWordChildren();
17341 domToHTML : function(currentElement, depth, nopadtext) {
17343 depth = depth || 0;
17344 nopadtext = nopadtext || false;
17346 if (!currentElement) {
17347 return this.domToHTML(this.doc.body);
17350 //Roo.log(currentElement);
17352 var allText = false;
17353 var nodeName = currentElement.nodeName;
17354 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17356 if (nodeName == '#text') {
17357 return currentElement.nodeValue;
17362 if (nodeName != 'BODY') {
17365 // Prints the node tagName, such as <A>, <IMG>, etc
17368 for(i = 0; i < currentElement.attributes.length;i++) {
17370 var aname = currentElement.attributes.item(i).name;
17371 if (!currentElement.attributes.item(i).value.length) {
17374 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17377 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17386 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17389 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17394 // Traverse the tree
17396 var currentElementChild = currentElement.childNodes.item(i);
17397 var allText = true;
17398 var innerHTML = '';
17400 while (currentElementChild) {
17401 // Formatting code (indent the tree so it looks nice on the screen)
17402 var nopad = nopadtext;
17403 if (lastnode == 'SPAN') {
17407 if (currentElementChild.nodeName == '#text') {
17408 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17409 if (!nopad && toadd.length > 80) {
17410 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17412 innerHTML += toadd;
17415 currentElementChild = currentElement.childNodes.item(i);
17421 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17423 // Recursively traverse the tree structure of the child node
17424 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17425 lastnode = currentElementChild.nodeName;
17427 currentElementChild=currentElement.childNodes.item(i);
17433 // The remaining code is mostly for formatting the tree
17434 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17439 ret+= "</"+tagName+">";
17445 // hide stuff that is not compatible
17459 * @event specialkey
17463 * @cfg {String} fieldClass @hide
17466 * @cfg {String} focusClass @hide
17469 * @cfg {String} autoCreate @hide
17472 * @cfg {String} inputType @hide
17475 * @cfg {String} invalidClass @hide
17478 * @cfg {String} invalidText @hide
17481 * @cfg {String} msgFx @hide
17484 * @cfg {String} validateOnBlur @hide
17488 Roo.HtmlEditorCore.white = [
17489 'area', 'br', 'img', 'input', 'hr', 'wbr',
17491 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17492 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17493 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17494 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17495 'table', 'ul', 'xmp',
17497 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17500 'dir', 'menu', 'ol', 'ul', 'dl',
17506 Roo.HtmlEditorCore.black = [
17507 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17509 'base', 'basefont', 'bgsound', 'blink', 'body',
17510 'frame', 'frameset', 'head', 'html', 'ilayer',
17511 'iframe', 'layer', 'link', 'meta', 'object',
17512 'script', 'style' ,'title', 'xml' // clean later..
17514 Roo.HtmlEditorCore.clean = [
17515 'script', 'style', 'title', 'xml'
17517 Roo.HtmlEditorCore.remove = [
17522 Roo.HtmlEditorCore.ablack = [
17526 Roo.HtmlEditorCore.aclean = [
17527 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17531 Roo.HtmlEditorCore.pwhite= [
17532 'http', 'https', 'mailto'
17535 // white listed style attributes.
17536 Roo.HtmlEditorCore.cwhite= [
17537 // 'text-align', /// default is to allow most things..
17543 // black listed style attributes.
17544 Roo.HtmlEditorCore.cblack= [
17545 // 'font-size' -- this can be set by the project
17549 Roo.HtmlEditorCore.swapCodes =[
17568 * @class Roo.bootstrap.HtmlEditor
17569 * @extends Roo.bootstrap.TextArea
17570 * Bootstrap HtmlEditor class
17573 * Create a new HtmlEditor
17574 * @param {Object} config The config object
17577 Roo.bootstrap.HtmlEditor = function(config){
17578 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17579 if (!this.toolbars) {
17580 this.toolbars = [];
17582 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17585 * @event initialize
17586 * Fires when the editor is fully initialized (including the iframe)
17587 * @param {HtmlEditor} this
17592 * Fires when the editor is first receives the focus. Any insertion must wait
17593 * until after this event.
17594 * @param {HtmlEditor} this
17598 * @event beforesync
17599 * Fires before the textarea is updated with content from the editor iframe. Return false
17600 * to cancel the sync.
17601 * @param {HtmlEditor} this
17602 * @param {String} html
17606 * @event beforepush
17607 * Fires before the iframe editor is updated with content from the textarea. Return false
17608 * to cancel the push.
17609 * @param {HtmlEditor} this
17610 * @param {String} html
17615 * Fires when the textarea is updated with content from the editor iframe.
17616 * @param {HtmlEditor} this
17617 * @param {String} html
17622 * Fires when the iframe editor is updated with content from the textarea.
17623 * @param {HtmlEditor} this
17624 * @param {String} html
17628 * @event editmodechange
17629 * Fires when the editor switches edit modes
17630 * @param {HtmlEditor} this
17631 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17633 editmodechange: true,
17635 * @event editorevent
17636 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17637 * @param {HtmlEditor} this
17641 * @event firstfocus
17642 * Fires when on first focus - needed by toolbars..
17643 * @param {HtmlEditor} this
17648 * Auto save the htmlEditor value as a file into Events
17649 * @param {HtmlEditor} this
17653 * @event savedpreview
17654 * preview the saved version of htmlEditor
17655 * @param {HtmlEditor} this
17662 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17666 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17671 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17676 * @cfg {Number} height (in pixels)
17680 * @cfg {Number} width (in pixels)
17685 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17688 stylesheets: false,
17693 // private properties
17694 validationEvent : false,
17696 initialized : false,
17699 onFocus : Roo.emptyFn,
17701 hideMode:'offsets',
17704 tbContainer : false,
17706 toolbarContainer :function() {
17707 return this.wrap.select('.x-html-editor-tb',true).first();
17711 * Protected method that will not generally be called directly. It
17712 * is called when the editor creates its toolbar. Override this method if you need to
17713 * add custom toolbar buttons.
17714 * @param {HtmlEditor} editor
17716 createToolbar : function(){
17718 Roo.log("create toolbars");
17720 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17721 this.toolbars[0].render(this.toolbarContainer());
17725 // if (!editor.toolbars || !editor.toolbars.length) {
17726 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17729 // for (var i =0 ; i < editor.toolbars.length;i++) {
17730 // editor.toolbars[i] = Roo.factory(
17731 // typeof(editor.toolbars[i]) == 'string' ?
17732 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
17733 // Roo.bootstrap.HtmlEditor);
17734 // editor.toolbars[i].init(editor);
17740 onRender : function(ct, position)
17742 // Roo.log("Call onRender: " + this.xtype);
17744 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17746 this.wrap = this.inputEl().wrap({
17747 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17750 this.editorcore.onRender(ct, position);
17752 if (this.resizable) {
17753 this.resizeEl = new Roo.Resizable(this.wrap, {
17757 minHeight : this.height,
17758 height: this.height,
17759 handles : this.resizable,
17762 resize : function(r, w, h) {
17763 _t.onResize(w,h); // -something
17769 this.createToolbar(this);
17772 if(!this.width && this.resizable){
17773 this.setSize(this.wrap.getSize());
17775 if (this.resizeEl) {
17776 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17777 // should trigger onReize..
17783 onResize : function(w, h)
17785 Roo.log('resize: ' +w + ',' + h );
17786 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17790 if(this.inputEl() ){
17791 if(typeof w == 'number'){
17792 var aw = w - this.wrap.getFrameWidth('lr');
17793 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17796 if(typeof h == 'number'){
17797 var tbh = -11; // fixme it needs to tool bar size!
17798 for (var i =0; i < this.toolbars.length;i++) {
17799 // fixme - ask toolbars for heights?
17800 tbh += this.toolbars[i].el.getHeight();
17801 //if (this.toolbars[i].footer) {
17802 // tbh += this.toolbars[i].footer.el.getHeight();
17810 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17811 ah -= 5; // knock a few pixes off for look..
17812 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17816 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17817 this.editorcore.onResize(ew,eh);
17822 * Toggles the editor between standard and source edit mode.
17823 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17825 toggleSourceEdit : function(sourceEditMode)
17827 this.editorcore.toggleSourceEdit(sourceEditMode);
17829 if(this.editorcore.sourceEditMode){
17830 Roo.log('editor - showing textarea');
17833 // Roo.log(this.syncValue());
17835 this.inputEl().removeClass(['hide', 'x-hidden']);
17836 this.inputEl().dom.removeAttribute('tabIndex');
17837 this.inputEl().focus();
17839 Roo.log('editor - hiding textarea');
17841 // Roo.log(this.pushValue());
17844 this.inputEl().addClass(['hide', 'x-hidden']);
17845 this.inputEl().dom.setAttribute('tabIndex', -1);
17846 //this.deferFocus();
17849 if(this.resizable){
17850 this.setSize(this.wrap.getSize());
17853 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
17856 // private (for BoxComponent)
17857 adjustSize : Roo.BoxComponent.prototype.adjustSize,
17859 // private (for BoxComponent)
17860 getResizeEl : function(){
17864 // private (for BoxComponent)
17865 getPositionEl : function(){
17870 initEvents : function(){
17871 this.originalValue = this.getValue();
17875 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17878 // markInvalid : Roo.emptyFn,
17880 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17883 // clearInvalid : Roo.emptyFn,
17885 setValue : function(v){
17886 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
17887 this.editorcore.pushValue();
17892 deferFocus : function(){
17893 this.focus.defer(10, this);
17897 focus : function(){
17898 this.editorcore.focus();
17904 onDestroy : function(){
17910 for (var i =0; i < this.toolbars.length;i++) {
17911 // fixme - ask toolbars for heights?
17912 this.toolbars[i].onDestroy();
17915 this.wrap.dom.innerHTML = '';
17916 this.wrap.remove();
17921 onFirstFocus : function(){
17922 //Roo.log("onFirstFocus");
17923 this.editorcore.onFirstFocus();
17924 for (var i =0; i < this.toolbars.length;i++) {
17925 this.toolbars[i].onFirstFocus();
17931 syncValue : function()
17933 this.editorcore.syncValue();
17936 pushValue : function()
17938 this.editorcore.pushValue();
17942 // hide stuff that is not compatible
17956 * @event specialkey
17960 * @cfg {String} fieldClass @hide
17963 * @cfg {String} focusClass @hide
17966 * @cfg {String} autoCreate @hide
17969 * @cfg {String} inputType @hide
17972 * @cfg {String} invalidClass @hide
17975 * @cfg {String} invalidText @hide
17978 * @cfg {String} msgFx @hide
17981 * @cfg {String} validateOnBlur @hide
17990 Roo.namespace('Roo.bootstrap.htmleditor');
17992 * @class Roo.bootstrap.HtmlEditorToolbar1
17997 new Roo.bootstrap.HtmlEditor({
18000 new Roo.bootstrap.HtmlEditorToolbar1({
18001 disable : { fonts: 1 , format: 1, ..., ... , ...],
18007 * @cfg {Object} disable List of elements to disable..
18008 * @cfg {Array} btns List of additional buttons.
18012 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
18015 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
18018 Roo.apply(this, config);
18020 // default disabled, based on 'good practice'..
18021 this.disable = this.disable || {};
18022 Roo.applyIf(this.disable, {
18025 specialElements : true
18027 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18029 this.editor = config.editor;
18030 this.editorcore = config.editor.editorcore;
18032 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18034 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18035 // dont call parent... till later.
18037 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18042 editorcore : false,
18047 "h1","h2","h3","h4","h5","h6",
18049 "abbr", "acronym", "address", "cite", "samp", "var",
18053 onRender : function(ct, position)
18055 // Roo.log("Call onRender: " + this.xtype);
18057 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18059 this.el.dom.style.marginBottom = '0';
18061 var editorcore = this.editorcore;
18062 var editor= this.editor;
18065 var btn = function(id,cmd , toggle, handler){
18067 var event = toggle ? 'toggle' : 'click';
18072 xns: Roo.bootstrap,
18075 enableToggle:toggle !== false,
18077 pressed : toggle ? false : null,
18080 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18081 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18090 xns: Roo.bootstrap,
18091 glyphicon : 'font',
18095 xns: Roo.bootstrap,
18099 Roo.each(this.formats, function(f) {
18100 style.menu.items.push({
18102 xns: Roo.bootstrap,
18103 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18108 editorcore.insertTag(this.tagname);
18115 children.push(style);
18118 btn('bold',false,true);
18119 btn('italic',false,true);
18120 btn('align-left', 'justifyleft',true);
18121 btn('align-center', 'justifycenter',true);
18122 btn('align-right' , 'justifyright',true);
18123 btn('link', false, false, function(btn) {
18124 //Roo.log("create link?");
18125 var url = prompt(this.createLinkText, this.defaultLinkValue);
18126 if(url && url != 'http:/'+'/'){
18127 this.editorcore.relayCmd('createlink', url);
18130 btn('list','insertunorderedlist',true);
18131 btn('pencil', false,true, function(btn){
18134 this.toggleSourceEdit(btn.pressed);
18140 xns: Roo.bootstrap,
18145 xns: Roo.bootstrap,
18150 cog.menu.items.push({
18152 xns: Roo.bootstrap,
18153 html : Clean styles,
18158 editorcore.insertTag(this.tagname);
18167 this.xtype = 'NavSimplebar';
18169 for(var i=0;i< children.length;i++) {
18171 this.buttons.add(this.addxtypeChild(children[i]));
18175 editor.on('editorevent', this.updateToolbar, this);
18177 onBtnClick : function(id)
18179 this.editorcore.relayCmd(id);
18180 this.editorcore.focus();
18184 * Protected method that will not generally be called directly. It triggers
18185 * a toolbar update by reading the markup state of the current selection in the editor.
18187 updateToolbar: function(){
18189 if(!this.editorcore.activated){
18190 this.editor.onFirstFocus(); // is this neeed?
18194 var btns = this.buttons;
18195 var doc = this.editorcore.doc;
18196 btns.get('bold').setActive(doc.queryCommandState('bold'));
18197 btns.get('italic').setActive(doc.queryCommandState('italic'));
18198 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18200 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18201 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18202 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18204 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18205 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18208 var ans = this.editorcore.getAllAncestors();
18209 if (this.formatCombo) {
18212 var store = this.formatCombo.store;
18213 this.formatCombo.setValue("");
18214 for (var i =0; i < ans.length;i++) {
18215 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18217 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18225 // hides menus... - so this cant be on a menu...
18226 Roo.bootstrap.MenuMgr.hideAll();
18228 Roo.bootstrap.MenuMgr.hideAll();
18229 //this.editorsyncValue();
18231 onFirstFocus: function() {
18232 this.buttons.each(function(item){
18236 toggleSourceEdit : function(sourceEditMode){
18239 if(sourceEditMode){
18240 Roo.log("disabling buttons");
18241 this.buttons.each( function(item){
18242 if(item.cmd != 'pencil'){
18248 Roo.log("enabling buttons");
18249 if(this.editorcore.initialized){
18250 this.buttons.each( function(item){
18256 Roo.log("calling toggole on editor");
18257 // tell the editor that it's been pressed..
18258 this.editor.toggleSourceEdit(sourceEditMode);
18268 * @class Roo.bootstrap.Table.AbstractSelectionModel
18269 * @extends Roo.util.Observable
18270 * Abstract base class for grid SelectionModels. It provides the interface that should be
18271 * implemented by descendant classes. This class should not be directly instantiated.
18274 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18275 this.locked = false;
18276 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18280 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18281 /** @ignore Called by the grid automatically. Do not call directly. */
18282 init : function(grid){
18288 * Locks the selections.
18291 this.locked = true;
18295 * Unlocks the selections.
18297 unlock : function(){
18298 this.locked = false;
18302 * Returns true if the selections are locked.
18303 * @return {Boolean}
18305 isLocked : function(){
18306 return this.locked;
18310 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18311 * @class Roo.bootstrap.Table.RowSelectionModel
18312 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18313 * It supports multiple selections and keyboard selection/navigation.
18315 * @param {Object} config
18318 Roo.bootstrap.Table.RowSelectionModel = function(config){
18319 Roo.apply(this, config);
18320 this.selections = new Roo.util.MixedCollection(false, function(o){
18325 this.lastActive = false;
18329 * @event selectionchange
18330 * Fires when the selection changes
18331 * @param {SelectionModel} this
18333 "selectionchange" : true,
18335 * @event afterselectionchange
18336 * Fires after the selection changes (eg. by key press or clicking)
18337 * @param {SelectionModel} this
18339 "afterselectionchange" : true,
18341 * @event beforerowselect
18342 * Fires when a row is selected being selected, return false to cancel.
18343 * @param {SelectionModel} this
18344 * @param {Number} rowIndex The selected index
18345 * @param {Boolean} keepExisting False if other selections will be cleared
18347 "beforerowselect" : true,
18350 * Fires when a row is selected.
18351 * @param {SelectionModel} this
18352 * @param {Number} rowIndex The selected index
18353 * @param {Roo.data.Record} r The record
18355 "rowselect" : true,
18357 * @event rowdeselect
18358 * Fires when a row is deselected.
18359 * @param {SelectionModel} this
18360 * @param {Number} rowIndex The selected index
18362 "rowdeselect" : true
18364 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18365 this.locked = false;
18368 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18370 * @cfg {Boolean} singleSelect
18371 * True to allow selection of only one row at a time (defaults to false)
18373 singleSelect : false,
18376 initEvents : function(){
18378 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18379 this.grid.on("mousedown", this.handleMouseDown, this);
18380 }else{ // allow click to work like normal
18381 this.grid.on("rowclick", this.handleDragableRowClick, this);
18384 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18385 "up" : function(e){
18387 this.selectPrevious(e.shiftKey);
18388 }else if(this.last !== false && this.lastActive !== false){
18389 var last = this.last;
18390 this.selectRange(this.last, this.lastActive-1);
18391 this.grid.getView().focusRow(this.lastActive);
18392 if(last !== false){
18396 this.selectFirstRow();
18398 this.fireEvent("afterselectionchange", this);
18400 "down" : function(e){
18402 this.selectNext(e.shiftKey);
18403 }else if(this.last !== false && this.lastActive !== false){
18404 var last = this.last;
18405 this.selectRange(this.last, this.lastActive+1);
18406 this.grid.getView().focusRow(this.lastActive);
18407 if(last !== false){
18411 this.selectFirstRow();
18413 this.fireEvent("afterselectionchange", this);
18418 var view = this.grid.view;
18419 view.on("refresh", this.onRefresh, this);
18420 view.on("rowupdated", this.onRowUpdated, this);
18421 view.on("rowremoved", this.onRemove, this);
18425 onRefresh : function(){
18426 var ds = this.grid.dataSource, i, v = this.grid.view;
18427 var s = this.selections;
18428 s.each(function(r){
18429 if((i = ds.indexOfId(r.id)) != -1){
18438 onRemove : function(v, index, r){
18439 this.selections.remove(r);
18443 onRowUpdated : function(v, index, r){
18444 if(this.isSelected(r)){
18445 v.onRowSelect(index);
18451 * @param {Array} records The records to select
18452 * @param {Boolean} keepExisting (optional) True to keep existing selections
18454 selectRecords : function(records, keepExisting){
18456 this.clearSelections();
18458 var ds = this.grid.dataSource;
18459 for(var i = 0, len = records.length; i < len; i++){
18460 this.selectRow(ds.indexOf(records[i]), true);
18465 * Gets the number of selected rows.
18468 getCount : function(){
18469 return this.selections.length;
18473 * Selects the first row in the grid.
18475 selectFirstRow : function(){
18480 * Select the last row.
18481 * @param {Boolean} keepExisting (optional) True to keep existing selections
18483 selectLastRow : function(keepExisting){
18484 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18488 * Selects the row immediately following the last selected row.
18489 * @param {Boolean} keepExisting (optional) True to keep existing selections
18491 selectNext : function(keepExisting){
18492 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18493 this.selectRow(this.last+1, keepExisting);
18494 this.grid.getView().focusRow(this.last);
18499 * Selects the row that precedes the last selected row.
18500 * @param {Boolean} keepExisting (optional) True to keep existing selections
18502 selectPrevious : function(keepExisting){
18504 this.selectRow(this.last-1, keepExisting);
18505 this.grid.getView().focusRow(this.last);
18510 * Returns the selected records
18511 * @return {Array} Array of selected records
18513 getSelections : function(){
18514 return [].concat(this.selections.items);
18518 * Returns the first selected record.
18521 getSelected : function(){
18522 return this.selections.itemAt(0);
18527 * Clears all selections.
18529 clearSelections : function(fast){
18530 if(this.locked) return;
18532 var ds = this.grid.dataSource;
18533 var s = this.selections;
18534 s.each(function(r){
18535 this.deselectRow(ds.indexOfId(r.id));
18539 this.selections.clear();
18546 * Selects all rows.
18548 selectAll : function(){
18549 if(this.locked) return;
18550 this.selections.clear();
18551 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18552 this.selectRow(i, true);
18557 * Returns True if there is a selection.
18558 * @return {Boolean}
18560 hasSelection : function(){
18561 return this.selections.length > 0;
18565 * Returns True if the specified row is selected.
18566 * @param {Number/Record} record The record or index of the record to check
18567 * @return {Boolean}
18569 isSelected : function(index){
18570 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18571 return (r && this.selections.key(r.id) ? true : false);
18575 * Returns True if the specified record id is selected.
18576 * @param {String} id The id of record to check
18577 * @return {Boolean}
18579 isIdSelected : function(id){
18580 return (this.selections.key(id) ? true : false);
18584 handleMouseDown : function(e, t){
18585 var view = this.grid.getView(), rowIndex;
18586 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18589 if(e.shiftKey && this.last !== false){
18590 var last = this.last;
18591 this.selectRange(last, rowIndex, e.ctrlKey);
18592 this.last = last; // reset the last
18593 view.focusRow(rowIndex);
18595 var isSelected = this.isSelected(rowIndex);
18596 if(e.button !== 0 && isSelected){
18597 view.focusRow(rowIndex);
18598 }else if(e.ctrlKey && isSelected){
18599 this.deselectRow(rowIndex);
18600 }else if(!isSelected){
18601 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18602 view.focusRow(rowIndex);
18605 this.fireEvent("afterselectionchange", this);
18608 handleDragableRowClick : function(grid, rowIndex, e)
18610 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18611 this.selectRow(rowIndex, false);
18612 grid.view.focusRow(rowIndex);
18613 this.fireEvent("afterselectionchange", this);
18618 * Selects multiple rows.
18619 * @param {Array} rows Array of the indexes of the row to select
18620 * @param {Boolean} keepExisting (optional) True to keep existing selections
18622 selectRows : function(rows, keepExisting){
18624 this.clearSelections();
18626 for(var i = 0, len = rows.length; i < len; i++){
18627 this.selectRow(rows[i], true);
18632 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18633 * @param {Number} startRow The index of the first row in the range
18634 * @param {Number} endRow The index of the last row in the range
18635 * @param {Boolean} keepExisting (optional) True to retain existing selections
18637 selectRange : function(startRow, endRow, keepExisting){
18638 if(this.locked) return;
18640 this.clearSelections();
18642 if(startRow <= endRow){
18643 for(var i = startRow; i <= endRow; i++){
18644 this.selectRow(i, true);
18647 for(var i = startRow; i >= endRow; i--){
18648 this.selectRow(i, true);
18654 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18655 * @param {Number} startRow The index of the first row in the range
18656 * @param {Number} endRow The index of the last row in the range
18658 deselectRange : function(startRow, endRow, preventViewNotify){
18659 if(this.locked) return;
18660 for(var i = startRow; i <= endRow; i++){
18661 this.deselectRow(i, preventViewNotify);
18667 * @param {Number} row The index of the row to select
18668 * @param {Boolean} keepExisting (optional) True to keep existing selections
18670 selectRow : function(index, keepExisting, preventViewNotify){
18671 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18672 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18673 if(!keepExisting || this.singleSelect){
18674 this.clearSelections();
18676 var r = this.grid.dataSource.getAt(index);
18677 this.selections.add(r);
18678 this.last = this.lastActive = index;
18679 if(!preventViewNotify){
18680 this.grid.getView().onRowSelect(index);
18682 this.fireEvent("rowselect", this, index, r);
18683 this.fireEvent("selectionchange", this);
18689 * @param {Number} row The index of the row to deselect
18691 deselectRow : function(index, preventViewNotify){
18692 if(this.locked) return;
18693 if(this.last == index){
18696 if(this.lastActive == index){
18697 this.lastActive = false;
18699 var r = this.grid.dataSource.getAt(index);
18700 this.selections.remove(r);
18701 if(!preventViewNotify){
18702 this.grid.getView().onRowDeselect(index);
18704 this.fireEvent("rowdeselect", this, index);
18705 this.fireEvent("selectionchange", this);
18709 restoreLast : function(){
18711 this.last = this._last;
18716 acceptsNav : function(row, col, cm){
18717 return !cm.isHidden(col) && cm.isCellEditable(col, row);
18721 onEditorKey : function(field, e){
18722 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18727 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18729 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18731 }else if(k == e.ENTER && !e.ctrlKey){
18735 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18737 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18739 }else if(k == e.ESC){
18743 g.startEditing(newCell[0], newCell[1]);
18748 * Ext JS Library 1.1.1
18749 * Copyright(c) 2006-2007, Ext JS, LLC.
18751 * Originally Released Under LGPL - original licence link has changed is not relivant.
18754 * <script type="text/javascript">
18758 * @class Roo.bootstrap.PagingToolbar
18760 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18762 * Create a new PagingToolbar
18763 * @param {Object} config The config object
18765 Roo.bootstrap.PagingToolbar = function(config)
18767 // old args format still supported... - xtype is prefered..
18768 // created from xtype...
18769 var ds = config.dataSource;
18770 this.toolbarItems = [];
18771 if (config.items) {
18772 this.toolbarItems = config.items;
18773 // config.items = [];
18776 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18783 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18787 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18789 * @cfg {Roo.data.Store} dataSource
18790 * The underlying data store providing the paged data
18793 * @cfg {String/HTMLElement/Element} container
18794 * container The id or element that will contain the toolbar
18797 * @cfg {Boolean} displayInfo
18798 * True to display the displayMsg (defaults to false)
18801 * @cfg {Number} pageSize
18802 * The number of records to display per page (defaults to 20)
18806 * @cfg {String} displayMsg
18807 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18809 displayMsg : 'Displaying {0} - {1} of {2}',
18811 * @cfg {String} emptyMsg
18812 * The message to display when no records are found (defaults to "No data to display")
18814 emptyMsg : 'No data to display',
18816 * Customizable piece of the default paging text (defaults to "Page")
18819 beforePageText : "Page",
18821 * Customizable piece of the default paging text (defaults to "of %0")
18824 afterPageText : "of {0}",
18826 * Customizable piece of the default paging text (defaults to "First Page")
18829 firstText : "First Page",
18831 * Customizable piece of the default paging text (defaults to "Previous Page")
18834 prevText : "Previous Page",
18836 * Customizable piece of the default paging text (defaults to "Next Page")
18839 nextText : "Next Page",
18841 * Customizable piece of the default paging text (defaults to "Last Page")
18844 lastText : "Last Page",
18846 * Customizable piece of the default paging text (defaults to "Refresh")
18849 refreshText : "Refresh",
18853 onRender : function(ct, position)
18855 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
18856 this.navgroup.parentId = this.id;
18857 this.navgroup.onRender(this.el, null);
18858 // add the buttons to the navgroup
18860 if(this.displayInfo){
18861 Roo.log(this.el.select('ul.navbar-nav',true).first());
18862 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
18863 this.displayEl = this.el.select('.x-paging-info', true).first();
18864 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
18865 // this.displayEl = navel.el.select('span',true).first();
18871 Roo.each(_this.buttons, function(e){
18872 Roo.factory(e).onRender(_this.el, null);
18876 Roo.each(_this.toolbarItems, function(e) {
18877 _this.navgroup.addItem(e);
18880 this.first = this.navgroup.addItem({
18881 tooltip: this.firstText,
18883 icon : 'fa fa-backward',
18885 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
18888 this.prev = this.navgroup.addItem({
18889 tooltip: this.prevText,
18891 icon : 'fa fa-step-backward',
18893 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
18895 //this.addSeparator();
18898 var field = this.navgroup.addItem( {
18900 cls : 'x-paging-position',
18902 html : this.beforePageText +
18903 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
18904 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
18907 this.field = field.el.select('input', true).first();
18908 this.field.on("keydown", this.onPagingKeydown, this);
18909 this.field.on("focus", function(){this.dom.select();});
18912 this.afterTextEl = field.el.select('.x-paging-after',true).first();
18913 //this.field.setHeight(18);
18914 //this.addSeparator();
18915 this.next = this.navgroup.addItem({
18916 tooltip: this.nextText,
18918 html : ' <i class="fa fa-step-forward">',
18920 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
18922 this.last = this.navgroup.addItem({
18923 tooltip: this.lastText,
18924 icon : 'fa fa-forward',
18927 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
18929 //this.addSeparator();
18930 this.loading = this.navgroup.addItem({
18931 tooltip: this.refreshText,
18932 icon: 'fa fa-refresh',
18934 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
18940 updateInfo : function(){
18941 if(this.displayEl){
18942 var count = this.ds.getCount();
18943 var msg = count == 0 ?
18947 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
18949 this.displayEl.update(msg);
18954 onLoad : function(ds, r, o){
18955 this.cursor = o.params ? o.params.start : 0;
18956 var d = this.getPageData(),
18960 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
18961 this.field.dom.value = ap;
18962 this.first.setDisabled(ap == 1);
18963 this.prev.setDisabled(ap == 1);
18964 this.next.setDisabled(ap == ps);
18965 this.last.setDisabled(ap == ps);
18966 this.loading.enable();
18971 getPageData : function(){
18972 var total = this.ds.getTotalCount();
18975 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
18976 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
18981 onLoadError : function(){
18982 this.loading.enable();
18986 onPagingKeydown : function(e){
18987 var k = e.getKey();
18988 var d = this.getPageData();
18990 var v = this.field.dom.value, pageNum;
18991 if(!v || isNaN(pageNum = parseInt(v, 10))){
18992 this.field.dom.value = d.activePage;
18995 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
18996 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
18999 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))
19001 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
19002 this.field.dom.value = pageNum;
19003 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
19006 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19008 var v = this.field.dom.value, pageNum;
19009 var increment = (e.shiftKey) ? 10 : 1;
19010 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19012 if(!v || isNaN(pageNum = parseInt(v, 10))) {
19013 this.field.dom.value = d.activePage;
19016 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
19018 this.field.dom.value = parseInt(v, 10) + increment;
19019 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
19020 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19027 beforeLoad : function(){
19029 this.loading.disable();
19034 onClick : function(which){
19041 ds.load({params:{start: 0, limit: this.pageSize}});
19044 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19047 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19050 var total = ds.getTotalCount();
19051 var extra = total % this.pageSize;
19052 var lastStart = extra ? (total - extra) : total-this.pageSize;
19053 ds.load({params:{start: lastStart, limit: this.pageSize}});
19056 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19062 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19063 * @param {Roo.data.Store} store The data store to unbind
19065 unbind : function(ds){
19066 ds.un("beforeload", this.beforeLoad, this);
19067 ds.un("load", this.onLoad, this);
19068 ds.un("loadexception", this.onLoadError, this);
19069 ds.un("remove", this.updateInfo, this);
19070 ds.un("add", this.updateInfo, this);
19071 this.ds = undefined;
19075 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19076 * @param {Roo.data.Store} store The data store to bind
19078 bind : function(ds){
19079 ds.on("beforeload", this.beforeLoad, this);
19080 ds.on("load", this.onLoad, this);
19081 ds.on("loadexception", this.onLoadError, this);
19082 ds.on("remove", this.updateInfo, this);
19083 ds.on("add", this.updateInfo, this);
19094 * @class Roo.bootstrap.MessageBar
19095 * @extends Roo.bootstrap.Component
19096 * Bootstrap MessageBar class
19097 * @cfg {String} html contents of the MessageBar
19098 * @cfg {String} weight (info | success | warning | danger) default info
19099 * @cfg {String} beforeClass insert the bar before the given class
19100 * @cfg {Boolean} closable (true | false) default false
19101 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19104 * Create a new Element
19105 * @param {Object} config The config object
19108 Roo.bootstrap.MessageBar = function(config){
19109 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19112 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19118 beforeClass: 'bootstrap-sticky-wrap',
19120 getAutoCreate : function(){
19124 cls: 'alert alert-dismissable alert-' + this.weight,
19129 html: this.html || ''
19135 cfg.cls += ' alert-messages-fixed';
19149 onRender : function(ct, position)
19151 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19154 var cfg = Roo.apply({}, this.getAutoCreate());
19158 cfg.cls += ' ' + this.cls;
19161 cfg.style = this.style;
19163 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19165 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19168 this.el.select('>button.close').on('click', this.hide, this);
19174 if (!this.rendered) {
19180 this.fireEvent('show', this);
19186 if (!this.rendered) {
19192 this.fireEvent('hide', this);
19195 update : function()
19197 // var e = this.el.dom.firstChild;
19199 // if(this.closable){
19200 // e = e.nextSibling;
19203 // e.data = this.html || '';
19205 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19221 * @class Roo.bootstrap.Graph
19222 * @extends Roo.bootstrap.Component
19223 * Bootstrap Graph class
19227 @cfg {String} graphtype bar | vbar | pie
19228 @cfg {number} g_x coodinator | centre x (pie)
19229 @cfg {number} g_y coodinator | centre y (pie)
19230 @cfg {number} g_r radius (pie)
19231 @cfg {number} g_height height of the chart (respected by all elements in the set)
19232 @cfg {number} g_width width of the chart (respected by all elements in the set)
19233 @cfg {Object} title The title of the chart
19236 -opts (object) options for the chart
19238 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19239 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19241 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.
19242 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19244 o stretch (boolean)
19246 -opts (object) options for the pie
19249 o startAngle (number)
19250 o endAngle (number)
19254 * Create a new Input
19255 * @param {Object} config The config object
19258 Roo.bootstrap.Graph = function(config){
19259 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19265 * The img click event for the img.
19266 * @param {Roo.EventObject} e
19272 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19283 //g_colors: this.colors,
19290 getAutoCreate : function(){
19301 onRender : function(ct,position){
19302 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19303 this.raphael = Raphael(this.el.dom);
19305 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19306 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19307 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19308 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19310 r.text(160, 10, "Single Series Chart").attr(txtattr);
19311 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19312 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19313 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19315 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19316 r.barchart(330, 10, 300, 220, data1);
19317 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19318 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19321 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19322 // r.barchart(30, 30, 560, 250, xdata, {
19323 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19324 // axis : "0 0 1 1",
19325 // axisxlabels : xdata
19326 // //yvalues : cols,
19329 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19331 // this.load(null,xdata,{
19332 // axis : "0 0 1 1",
19333 // axisxlabels : xdata
19338 load : function(graphtype,xdata,opts){
19339 this.raphael.clear();
19341 graphtype = this.graphtype;
19346 var r = this.raphael,
19347 fin = function () {
19348 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19350 fout = function () {
19351 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19353 pfin = function() {
19354 this.sector.stop();
19355 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19358 this.label[0].stop();
19359 this.label[0].attr({ r: 7.5 });
19360 this.label[1].attr({ "font-weight": 800 });
19363 pfout = function() {
19364 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19367 this.label[0].animate({ r: 5 }, 500, "bounce");
19368 this.label[1].attr({ "font-weight": 400 });
19374 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19377 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19380 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
19381 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19383 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19390 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19395 setTitle: function(o)
19400 initEvents: function() {
19403 this.el.on('click', this.onClick, this);
19407 onClick : function(e)
19409 Roo.log('img onclick');
19410 this.fireEvent('click', this, e);
19422 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19425 * @class Roo.bootstrap.dash.NumberBox
19426 * @extends Roo.bootstrap.Component
19427 * Bootstrap NumberBox class
19428 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19429 * @cfg {String} headline Box headline
19430 * @cfg {String} content Box content
19431 * @cfg {String} icon Box icon
19432 * @cfg {String} footer Footer text
19433 * @cfg {String} fhref Footer href
19436 * Create a new NumberBox
19437 * @param {Object} config The config object
19441 Roo.bootstrap.dash.NumberBox = function(config){
19442 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19446 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19456 getAutoCreate : function(){
19460 cls : 'small-box bg-' + this.bgcolor,
19468 cls : 'roo-headline',
19469 html : this.headline
19473 cls : 'roo-content',
19474 html : this.content
19488 cls : 'ion ' + this.icon
19497 cls : 'small-box-footer',
19498 href : this.fhref || '#',
19502 cfg.cn.push(footer);
19509 onRender : function(ct,position){
19510 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19517 setHeadline: function (value)
19519 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19522 setFooter: function (value, href)
19524 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19527 this.el.select('a.small-box-footer',true).first().attr('href', href);
19532 setContent: function (value)
19534 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19537 initEvents: function()
19551 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19554 * @class Roo.bootstrap.dash.TabBox
19555 * @extends Roo.bootstrap.Component
19556 * Bootstrap TabBox class
19557 * @cfg {String} title Title of the TabBox
19558 * @cfg {String} icon Icon of the TabBox
19559 * @cfg {Boolean} showtabs (true|false) show the tabs default true
19562 * Create a new TabBox
19563 * @param {Object} config The config object
19567 Roo.bootstrap.dash.TabBox = function(config){
19568 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19573 * When a pane is added
19574 * @param {Roo.bootstrap.dash.TabPane} pane
19581 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19587 getChildContainer : function()
19589 return this.el.select('.tab-content', true).first();
19592 getAutoCreate : function(){
19596 cls: 'pull-left header',
19604 cls: 'fa ' + this.icon
19611 cls: 'nav-tabs-custom',
19615 cls: 'nav nav-tabs pull-right',
19622 cls: 'tab-content no-padding',
19630 initEvents : function()
19632 //Roo.log('add add pane handler');
19633 this.on('addpane', this.onAddPane, this);
19636 * Updates the box title
19637 * @param {String} html to set the title to.
19639 setTitle : function(value)
19641 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
19643 onAddPane : function(pane)
19645 //Roo.log('addpane');
19647 // tabs are rendere left to right..
19648 if(!this.showtabs){
19652 var ctr = this.el.select('.nav-tabs', true).first();
19655 var existing = ctr.select('.nav-tab',true);
19656 var qty = existing.getCount();;
19659 var tab = ctr.createChild({
19661 cls : 'nav-tab' + (qty ? '' : ' active'),
19669 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
19672 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
19674 pane.el.addClass('active');
19679 onTabClick : function(ev,un,ob,pane)
19681 //Roo.log('tab - prev default');
19682 ev.preventDefault();
19685 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
19686 pane.tab.addClass('active');
19687 //Roo.log(pane.title);
19688 this.getChildContainer().select('.tab-pane',true).removeClass('active');
19689 // technically we should have a deactivate event.. but maybe add later.
19690 // and it should not de-activate the selected tab...
19692 pane.el.addClass('active');
19693 pane.fireEvent('activate');
19708 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19710 * @class Roo.bootstrap.TabPane
19711 * @extends Roo.bootstrap.Component
19712 * Bootstrap TabPane class
19713 * @cfg {Boolean} active (false | true) Default false
19714 * @cfg {String} title title of panel
19718 * Create a new TabPane
19719 * @param {Object} config The config object
19722 Roo.bootstrap.dash.TabPane = function(config){
19723 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19727 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
19732 // the tabBox that this is attached to.
19735 getAutoCreate : function()
19743 cfg.cls += ' active';
19748 initEvents : function()
19750 //Roo.log('trigger add pane handler');
19751 this.parent().fireEvent('addpane', this)
19755 * Updates the tab title
19756 * @param {String} html to set the title to.
19758 setTitle: function(str)
19764 this.tab.select('a'.true).first().dom.innerHTML = str;
19781 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19784 * @class Roo.bootstrap.menu.Menu
19785 * @extends Roo.bootstrap.Component
19786 * Bootstrap Menu class - container for Menu
19787 * @cfg {String} html Text of the menu
19788 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19789 * @cfg {String} icon Font awesome icon
19790 * @cfg {String} pos Menu align to (top | bottom) default bottom
19794 * Create a new Menu
19795 * @param {Object} config The config object
19799 Roo.bootstrap.menu.Menu = function(config){
19800 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19804 * @event beforeshow
19805 * Fires before this menu is displayed
19806 * @param {Roo.bootstrap.menu.Menu} this
19810 * @event beforehide
19811 * Fires before this menu is hidden
19812 * @param {Roo.bootstrap.menu.Menu} this
19817 * Fires after this menu is displayed
19818 * @param {Roo.bootstrap.menu.Menu} this
19823 * Fires after this menu is hidden
19824 * @param {Roo.bootstrap.menu.Menu} this
19829 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19830 * @param {Roo.bootstrap.menu.Menu} this
19831 * @param {Roo.EventObject} e
19838 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
19842 weight : 'default',
19847 getChildContainer : function() {
19848 if(this.isSubMenu){
19852 return this.el.select('ul.dropdown-menu', true).first();
19855 getAutoCreate : function()
19860 cls : 'roo-menu-text',
19868 cls : 'fa ' + this.icon
19879 cls : 'dropdown-button btn btn-' + this.weight,
19884 cls : 'dropdown-toggle btn btn-' + this.weight,
19894 cls : 'dropdown-menu'
19900 if(this.pos == 'top'){
19901 cfg.cls += ' dropup';
19904 if(this.isSubMenu){
19907 cls : 'dropdown-menu'
19914 onRender : function(ct, position)
19916 this.isSubMenu = ct.hasClass('dropdown-submenu');
19918 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
19921 initEvents : function()
19923 if(this.isSubMenu){
19927 this.hidden = true;
19929 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
19930 this.triggerEl.on('click', this.onTriggerPress, this);
19932 this.buttonEl = this.el.select('button.dropdown-button', true).first();
19933 this.buttonEl.on('click', this.onClick, this);
19939 if(this.isSubMenu){
19943 return this.el.select('ul.dropdown-menu', true).first();
19946 onClick : function(e)
19948 this.fireEvent("click", this, e);
19951 onTriggerPress : function(e)
19953 if (this.isVisible()) {
19960 isVisible : function(){
19961 return !this.hidden;
19966 this.fireEvent("beforeshow", this);
19968 this.hidden = false;
19969 this.el.addClass('open');
19971 Roo.get(document).on("mouseup", this.onMouseUp, this);
19973 this.fireEvent("show", this);
19980 this.fireEvent("beforehide", this);
19982 this.hidden = true;
19983 this.el.removeClass('open');
19985 Roo.get(document).un("mouseup", this.onMouseUp);
19987 this.fireEvent("hide", this);
19990 onMouseUp : function()
20004 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20007 * @class Roo.bootstrap.menu.Item
20008 * @extends Roo.bootstrap.Component
20009 * Bootstrap MenuItem class
20010 * @cfg {Boolean} submenu (true | false) default false
20011 * @cfg {String} html text of the item
20012 * @cfg {String} href the link
20013 * @cfg {Boolean} disable (true | false) default false
20014 * @cfg {Boolean} preventDefault (true | false) default true
20015 * @cfg {String} icon Font awesome icon
20016 * @cfg {String} pos Submenu align to (left | right) default right
20020 * Create a new Item
20021 * @param {Object} config The config object
20025 Roo.bootstrap.menu.Item = function(config){
20026 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20030 * Fires when the mouse is hovering over this menu
20031 * @param {Roo.bootstrap.menu.Item} this
20032 * @param {Roo.EventObject} e
20037 * Fires when the mouse exits this menu
20038 * @param {Roo.bootstrap.menu.Item} this
20039 * @param {Roo.EventObject} e
20045 * The raw click event for the entire grid.
20046 * @param {Roo.EventObject} e
20052 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20057 preventDefault: true,
20062 getAutoCreate : function()
20067 cls : 'roo-menu-item-text',
20075 cls : 'fa ' + this.icon
20084 href : this.href || '#',
20091 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20095 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20097 if(this.pos == 'left'){
20098 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20105 initEvents : function()
20107 this.el.on('mouseover', this.onMouseOver, this);
20108 this.el.on('mouseout', this.onMouseOut, this);
20110 this.el.select('a', true).first().on('click', this.onClick, this);
20114 onClick : function(e)
20116 if(this.preventDefault){
20117 e.preventDefault();
20120 this.fireEvent("click", this, e);
20123 onMouseOver : function(e)
20125 if(this.submenu && this.pos == 'left'){
20126 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20129 this.fireEvent("mouseover", this, e);
20132 onMouseOut : function(e)
20134 this.fireEvent("mouseout", this, e);
20146 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20149 * @class Roo.bootstrap.menu.Separator
20150 * @extends Roo.bootstrap.Component
20151 * Bootstrap Separator class
20154 * Create a new Separator
20155 * @param {Object} config The config object
20159 Roo.bootstrap.menu.Separator = function(config){
20160 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20163 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20165 getAutoCreate : function(){