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() {
1161 this.el.on('click', this.onClick, this);
1165 onClick : function(e)
1167 if(this.preventDefault){
1170 //Roo.log('img onclick');
1171 this.fireEvent('click', this, e);
1184 * @class Roo.bootstrap.Header
1185 * @extends Roo.bootstrap.Component
1186 * Bootstrap Header class
1187 * @cfg {String} html content of header
1188 * @cfg {Number} level (1|2|3|4|5|6) default 1
1191 * Create a new Header
1192 * @param {Object} config The config object
1196 Roo.bootstrap.Header = function(config){
1197 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1200 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1208 getAutoCreate : function(){
1211 tag: 'h' + (1 *this.level),
1212 html: this.html || 'fill in html'
1224 * Ext JS Library 1.1.1
1225 * Copyright(c) 2006-2007, Ext JS, LLC.
1227 * Originally Released Under LGPL - original licence link has changed is not relivant.
1230 * <script type="text/javascript">
1234 * @class Roo.bootstrap.MenuMgr
1235 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1238 Roo.bootstrap.MenuMgr = function(){
1239 var menus, active, groups = {}, attached = false, lastShow = new Date();
1241 // private - called when first menu is created
1244 active = new Roo.util.MixedCollection();
1245 Roo.get(document).addKeyListener(27, function(){
1246 if(active.length > 0){
1254 if(active && active.length > 0){
1255 var c = active.clone();
1265 if(active.length < 1){
1266 Roo.get(document).un("mouseup", onMouseDown);
1274 var last = active.last();
1275 lastShow = new Date();
1278 Roo.get(document).on("mouseup", onMouseDown);
1283 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1284 m.parentMenu.activeChild = m;
1285 }else if(last && last.isVisible()){
1286 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1291 function onBeforeHide(m){
1293 m.activeChild.hide();
1295 if(m.autoHideTimer){
1296 clearTimeout(m.autoHideTimer);
1297 delete m.autoHideTimer;
1302 function onBeforeShow(m){
1303 var pm = m.parentMenu;
1304 if(!pm && !m.allowOtherMenus){
1306 }else if(pm && pm.activeChild && active != m){
1307 pm.activeChild.hide();
1312 function onMouseDown(e){
1313 Roo.log("on MouseDown");
1314 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1322 function onBeforeCheck(mi, state){
1324 var g = groups[mi.group];
1325 for(var i = 0, l = g.length; i < l; i++){
1327 g[i].setChecked(false);
1336 * Hides all menus that are currently visible
1338 hideAll : function(){
1343 register : function(menu){
1347 menus[menu.id] = menu;
1348 menu.on("beforehide", onBeforeHide);
1349 menu.on("hide", onHide);
1350 menu.on("beforeshow", onBeforeShow);
1351 menu.on("show", onShow);
1353 if(g && menu.events["checkchange"]){
1357 groups[g].push(menu);
1358 menu.on("checkchange", onCheck);
1363 * Returns a {@link Roo.menu.Menu} object
1364 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1365 * be used to generate and return a new Menu instance.
1367 get : function(menu){
1368 if(typeof menu == "string"){ // menu id
1370 }else if(menu.events){ // menu instance
1373 /*else if(typeof menu.length == 'number'){ // array of menu items?
1374 return new Roo.bootstrap.Menu({items:menu});
1375 }else{ // otherwise, must be a config
1376 return new Roo.bootstrap.Menu(menu);
1383 unregister : function(menu){
1384 delete menus[menu.id];
1385 menu.un("beforehide", onBeforeHide);
1386 menu.un("hide", onHide);
1387 menu.un("beforeshow", onBeforeShow);
1388 menu.un("show", onShow);
1390 if(g && menu.events["checkchange"]){
1391 groups[g].remove(menu);
1392 menu.un("checkchange", onCheck);
1397 registerCheckable : function(menuItem){
1398 var g = menuItem.group;
1403 groups[g].push(menuItem);
1404 menuItem.on("beforecheckchange", onBeforeCheck);
1409 unregisterCheckable : function(menuItem){
1410 var g = menuItem.group;
1412 groups[g].remove(menuItem);
1413 menuItem.un("beforecheckchange", onBeforeCheck);
1425 * @class Roo.bootstrap.Menu
1426 * @extends Roo.bootstrap.Component
1427 * Bootstrap Menu class - container for MenuItems
1428 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1432 * @param {Object} config The config object
1436 Roo.bootstrap.Menu = function(config){
1437 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1438 if (this.registerMenu) {
1439 Roo.bootstrap.MenuMgr.register(this);
1444 * Fires before this menu is displayed
1445 * @param {Roo.menu.Menu} this
1450 * Fires before this menu is hidden
1451 * @param {Roo.menu.Menu} this
1456 * Fires after this menu is displayed
1457 * @param {Roo.menu.Menu} this
1462 * Fires after this menu is hidden
1463 * @param {Roo.menu.Menu} this
1468 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1469 * @param {Roo.menu.Menu} this
1470 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1471 * @param {Roo.EventObject} e
1476 * Fires when the mouse is hovering over this menu
1477 * @param {Roo.menu.Menu} this
1478 * @param {Roo.EventObject} e
1479 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1484 * Fires when the mouse exits this menu
1485 * @param {Roo.menu.Menu} this
1486 * @param {Roo.EventObject} e
1487 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1492 * Fires when a menu item contained in this menu is clicked
1493 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1494 * @param {Roo.EventObject} e
1498 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1501 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1505 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1508 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1510 registerMenu : true,
1512 menuItems :false, // stores the menu items..
1518 getChildContainer : function() {
1522 getAutoCreate : function(){
1524 //if (['right'].indexOf(this.align)!==-1) {
1525 // cfg.cn[1].cls += ' pull-right'
1531 cls : 'dropdown-menu' ,
1532 style : 'z-index:1000'
1536 if (this.type === 'submenu') {
1537 cfg.cls = 'submenu active';
1539 if (this.type === 'treeview') {
1540 cfg.cls = 'treeview-menu';
1545 initEvents : function() {
1547 // Roo.log("ADD event");
1548 // Roo.log(this.triggerEl.dom);
1549 this.triggerEl.on('click', this.onTriggerPress, this);
1550 this.triggerEl.addClass('dropdown-toggle');
1551 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1553 this.el.on("mouseover", this.onMouseOver, this);
1554 this.el.on("mouseout", this.onMouseOut, this);
1558 findTargetItem : function(e){
1559 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1563 //Roo.log(t); Roo.log(t.id);
1565 //Roo.log(this.menuitems);
1566 return this.menuitems.get(t.id);
1568 //return this.items.get(t.menuItemId);
1573 onClick : function(e){
1574 Roo.log("menu.onClick");
1575 var t = this.findTargetItem(e);
1581 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1582 if(t == this.activeItem && t.shouldDeactivate(e)){
1583 this.activeItem.deactivate();
1584 delete this.activeItem;
1588 this.setActiveItem(t, true);
1595 Roo.log('pass click event');
1599 this.fireEvent("click", this, t, e);
1603 onMouseOver : function(e){
1604 var t = this.findTargetItem(e);
1607 // if(t.canActivate && !t.disabled){
1608 // this.setActiveItem(t, true);
1612 this.fireEvent("mouseover", this, e, t);
1614 isVisible : function(){
1615 return !this.hidden;
1617 onMouseOut : function(e){
1618 var t = this.findTargetItem(e);
1621 // if(t == this.activeItem && t.shouldDeactivate(e)){
1622 // this.activeItem.deactivate();
1623 // delete this.activeItem;
1626 this.fireEvent("mouseout", this, e, t);
1631 * Displays this menu relative to another element
1632 * @param {String/HTMLElement/Roo.Element} element The element to align to
1633 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1634 * the element (defaults to this.defaultAlign)
1635 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1637 show : function(el, pos, parentMenu){
1638 this.parentMenu = parentMenu;
1642 this.fireEvent("beforeshow", this);
1643 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1646 * Displays this menu at a specific xy position
1647 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1648 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1650 showAt : function(xy, parentMenu, /* private: */_e){
1651 this.parentMenu = parentMenu;
1656 this.fireEvent("beforeshow", this);
1658 //xy = this.el.adjustForConstraints(xy);
1660 //this.el.setXY(xy);
1662 this.hideMenuItems();
1663 this.hidden = false;
1664 this.triggerEl.addClass('open');
1666 this.fireEvent("show", this);
1672 this.doFocus.defer(50, this);
1676 doFocus : function(){
1678 this.focusEl.focus();
1683 * Hides this menu and optionally all parent menus
1684 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1686 hide : function(deep){
1688 this.hideMenuItems();
1689 if(this.el && this.isVisible()){
1690 this.fireEvent("beforehide", this);
1691 if(this.activeItem){
1692 this.activeItem.deactivate();
1693 this.activeItem = null;
1695 this.triggerEl.removeClass('open');;
1697 this.fireEvent("hide", this);
1699 if(deep === true && this.parentMenu){
1700 this.parentMenu.hide(true);
1704 onTriggerPress : function(e)
1707 Roo.log('trigger press');
1708 //Roo.log(e.getTarget());
1709 // Roo.log(this.triggerEl.dom);
1710 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1713 if (this.isVisible()) {
1717 this.show(this.triggerEl, false, false);
1726 hideMenuItems : function()
1728 //$(backdrop).remove()
1729 Roo.select('.open',true).each(function(aa) {
1731 aa.removeClass('open');
1732 //var parent = getParent($(this))
1733 //var relatedTarget = { relatedTarget: this }
1735 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1736 //if (e.isDefaultPrevented()) return
1737 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1740 addxtypeChild : function (tree, cntr) {
1741 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1743 this.menuitems.add(comp);
1764 * @class Roo.bootstrap.MenuItem
1765 * @extends Roo.bootstrap.Component
1766 * Bootstrap MenuItem class
1767 * @cfg {String} html the menu label
1768 * @cfg {String} href the link
1769 * @cfg {Boolean} preventDefault (true | false) default true
1773 * Create a new MenuItem
1774 * @param {Object} config The config object
1778 Roo.bootstrap.MenuItem = function(config){
1779 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1784 * The raw click event for the entire grid.
1785 * @param {Roo.EventObject} e
1791 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1795 preventDefault: true,
1797 getAutoCreate : function(){
1800 cls: 'dropdown-menu-item',
1809 if (this.parent().type == 'treeview') {
1810 cfg.cls = 'treeview-menu';
1813 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1814 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1818 initEvents: function() {
1820 //this.el.select('a').on('click', this.onClick, this);
1823 onClick : function(e)
1825 Roo.log('item on click ');
1826 //if(this.preventDefault){
1827 // e.preventDefault();
1829 //this.parent().hideMenuItems();
1831 this.fireEvent('click', this, e);
1850 * @class Roo.bootstrap.MenuSeparator
1851 * @extends Roo.bootstrap.Component
1852 * Bootstrap MenuSeparator class
1855 * Create a new MenuItem
1856 * @param {Object} config The config object
1860 Roo.bootstrap.MenuSeparator = function(config){
1861 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1864 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1866 getAutoCreate : function(){
1881 <div class="modal fade">
1882 <div class="modal-dialog">
1883 <div class="modal-content">
1884 <div class="modal-header">
1885 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1886 <h4 class="modal-title">Modal title</h4>
1888 <div class="modal-body">
1889 <p>One fine body…</p>
1891 <div class="modal-footer">
1892 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1893 <button type="button" class="btn btn-primary">Save changes</button>
1895 </div><!-- /.modal-content -->
1896 </div><!-- /.modal-dialog -->
1897 </div><!-- /.modal -->
1907 * @class Roo.bootstrap.Modal
1908 * @extends Roo.bootstrap.Component
1909 * Bootstrap Modal class
1910 * @cfg {String} title Title of dialog
1911 * @cfg {Boolean} specificTitle (true|false) default false
1912 * @cfg {Array} buttons Array of buttons or standard button set..
1913 * @cfg {String} buttonPosition (left|right|center) default right
1916 * Create a new Modal Dialog
1917 * @param {Object} config The config object
1920 Roo.bootstrap.Modal = function(config){
1921 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1926 * The raw btnclick event for the button
1927 * @param {Roo.EventObject} e
1931 this.buttons = this.buttons || [];
1934 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1936 title : 'test dialog',
1943 specificTitle: false,
1945 buttonPosition: 'right',
1947 onRender : function(ct, position)
1949 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1952 var cfg = Roo.apply({}, this.getAutoCreate());
1955 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1957 //if (!cfg.name.length) {
1961 cfg.cls += ' ' + this.cls;
1964 cfg.style = this.style;
1966 this.el = Roo.get(document.body).createChild(cfg, position);
1968 //var type = this.el.dom.type;
1970 if(this.tabIndex !== undefined){
1971 this.el.dom.setAttribute('tabIndex', this.tabIndex);
1976 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1977 this.maskEl.enableDisplayMode("block");
1979 //this.el.addClass("x-dlg-modal");
1981 if (this.buttons.length) {
1982 Roo.each(this.buttons, function(bb) {
1983 b = Roo.apply({}, bb);
1984 b.xns = b.xns || Roo.bootstrap;
1985 b.xtype = b.xtype || 'Button';
1986 if (typeof(b.listeners) == 'undefined') {
1987 b.listeners = { click : this.onButtonClick.createDelegate(this) };
1990 var btn = Roo.factory(b);
1992 btn.onRender(this.el.select('.modal-footer div').first());
1996 // render the children.
1999 if(typeof(this.items) != 'undefined'){
2000 var items = this.items;
2003 for(var i =0;i < items.length;i++) {
2004 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2008 this.items = nitems;
2010 this.body = this.el.select('.modal-body',true).first();
2011 this.close = this.el.select('.modal-header .close', true).first();
2012 this.footer = this.el.select('.modal-footer',true).first();
2014 //this.el.addClass([this.fieldClass, this.cls]);
2017 getAutoCreate : function(){
2022 html : this.html || ''
2027 cls : 'modal-title',
2031 if(this.specificTitle){
2037 style : 'display: none',
2040 cls: "modal-dialog",
2043 cls : "modal-content",
2046 cls : 'modal-header',
2058 cls : 'modal-footer',
2062 cls: 'btn-' + this.buttonPosition
2081 getChildContainer : function() {
2083 return this.el.select('.modal-body',true).first();
2086 getButtonContainer : function() {
2087 return this.el.select('.modal-footer div',true).first();
2090 initEvents : function()
2092 this.el.select('.modal-header .close').on('click', this.hide, this);
2094 // this.addxtype(this);
2098 if (!this.rendered) {
2102 this.el.addClass('on');
2103 this.el.removeClass('fade');
2104 this.el.setStyle('display', 'block');
2105 Roo.get(document.body).addClass("x-body-masked");
2106 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2108 this.el.setStyle('zIndex', '10001');
2109 this.fireEvent('show', this);
2115 Roo.log('Modal hide?!');
2117 Roo.get(document.body).removeClass("x-body-masked");
2118 this.el.removeClass('on');
2119 this.el.addClass('fade');
2120 this.el.setStyle('display', 'none');
2121 this.fireEvent('hide', this);
2124 addButton : function(str, cb)
2128 var b = Roo.apply({}, { html : str } );
2129 b.xns = b.xns || Roo.bootstrap;
2130 b.xtype = b.xtype || 'Button';
2131 if (typeof(b.listeners) == 'undefined') {
2132 b.listeners = { click : cb.createDelegate(this) };
2135 var btn = Roo.factory(b);
2137 btn.onRender(this.el.select('.modal-footer div').first());
2143 setDefaultButton : function(btn)
2145 //this.el.select('.modal-footer').()
2147 resizeTo: function(w,h)
2151 setContentSize : function(w, h)
2155 onButtonClick: function(btn,e)
2158 this.fireEvent('btnclick', btn.name, e);
2160 setTitle: function(str) {
2161 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2167 Roo.apply(Roo.bootstrap.Modal, {
2169 * Button config that displays a single OK button
2178 * Button config that displays Yes and No buttons
2194 * Button config that displays OK and Cancel buttons
2209 * Button config that displays Yes, No and Cancel buttons
2231 * messagebox - can be used as a replace
2235 * @class Roo.MessageBox
2236 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2240 Roo.Msg.alert('Status', 'Changes saved successfully.');
2242 // Prompt for user data:
2243 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2245 // process text value...
2249 // Show a dialog using config options:
2251 title:'Save Changes?',
2252 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2253 buttons: Roo.Msg.YESNOCANCEL,
2260 Roo.bootstrap.MessageBox = function(){
2261 var dlg, opt, mask, waitTimer;
2262 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2263 var buttons, activeTextEl, bwidth;
2267 var handleButton = function(button){
2269 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2273 var handleHide = function(){
2275 dlg.el.removeClass(opt.cls);
2278 // Roo.TaskMgr.stop(waitTimer);
2279 // waitTimer = null;
2284 var updateButtons = function(b){
2287 buttons["ok"].hide();
2288 buttons["cancel"].hide();
2289 buttons["yes"].hide();
2290 buttons["no"].hide();
2291 //dlg.footer.dom.style.display = 'none';
2294 dlg.footer.dom.style.display = '';
2295 for(var k in buttons){
2296 if(typeof buttons[k] != "function"){
2299 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2300 width += buttons[k].el.getWidth()+15;
2310 var handleEsc = function(d, k, e){
2311 if(opt && opt.closable !== false){
2321 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2322 * @return {Roo.BasicDialog} The BasicDialog element
2324 getDialog : function(){
2326 dlg = new Roo.bootstrap.Modal( {
2329 //constraintoviewport:false,
2331 //collapsible : false,
2336 //buttonAlign:"center",
2337 closeClick : function(){
2338 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2341 handleButton("cancel");
2346 dlg.on("hide", handleHide);
2348 //dlg.addKeyListener(27, handleEsc);
2350 this.buttons = buttons;
2351 var bt = this.buttonText;
2352 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2353 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2354 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2355 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2357 bodyEl = dlg.body.createChild({
2359 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2360 '<textarea class="roo-mb-textarea"></textarea>' +
2361 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2363 msgEl = bodyEl.dom.firstChild;
2364 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2365 textboxEl.enableDisplayMode();
2366 textboxEl.addKeyListener([10,13], function(){
2367 if(dlg.isVisible() && opt && opt.buttons){
2370 }else if(opt.buttons.yes){
2371 handleButton("yes");
2375 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2376 textareaEl.enableDisplayMode();
2377 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2378 progressEl.enableDisplayMode();
2379 var pf = progressEl.dom.firstChild;
2381 pp = Roo.get(pf.firstChild);
2382 pp.setHeight(pf.offsetHeight);
2390 * Updates the message box body text
2391 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2392 * the XHTML-compliant non-breaking space character '&#160;')
2393 * @return {Roo.MessageBox} This message box
2395 updateText : function(text){
2396 if(!dlg.isVisible() && !opt.width){
2397 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2399 msgEl.innerHTML = text || ' ';
2401 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2402 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2404 Math.min(opt.width || cw , this.maxWidth),
2405 Math.max(opt.minWidth || this.minWidth, bwidth)
2408 activeTextEl.setWidth(w);
2410 if(dlg.isVisible()){
2411 dlg.fixedcenter = false;
2413 // to big, make it scroll. = But as usual stupid IE does not support
2416 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2417 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2418 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2420 bodyEl.dom.style.height = '';
2421 bodyEl.dom.style.overflowY = '';
2424 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2426 bodyEl.dom.style.overflowX = '';
2429 dlg.setContentSize(w, bodyEl.getHeight());
2430 if(dlg.isVisible()){
2431 dlg.fixedcenter = true;
2437 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2438 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2439 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2440 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2441 * @return {Roo.MessageBox} This message box
2443 updateProgress : function(value, text){
2445 this.updateText(text);
2447 if (pp) { // weird bug on my firefox - for some reason this is not defined
2448 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2454 * Returns true if the message box is currently displayed
2455 * @return {Boolean} True if the message box is visible, else false
2457 isVisible : function(){
2458 return dlg && dlg.isVisible();
2462 * Hides the message box if it is displayed
2465 if(this.isVisible()){
2471 * Displays a new message box, or reinitializes an existing message box, based on the config options
2472 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2473 * The following config object properties are supported:
2475 Property Type Description
2476 ---------- --------------- ------------------------------------------------------------------------------------
2477 animEl String/Element An id or Element from which the message box should animate as it opens and
2478 closes (defaults to undefined)
2479 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2480 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2481 closable Boolean False to hide the top-right close button (defaults to true). Note that
2482 progress and wait dialogs will ignore this property and always hide the
2483 close button as they can only be closed programmatically.
2484 cls String A custom CSS class to apply to the message box element
2485 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2486 displayed (defaults to 75)
2487 fn Function A callback function to execute after closing the dialog. The arguments to the
2488 function will be btn (the name of the button that was clicked, if applicable,
2489 e.g. "ok"), and text (the value of the active text field, if applicable).
2490 Progress and wait dialogs will ignore this option since they do not respond to
2491 user actions and can only be closed programmatically, so any required function
2492 should be called by the same code after it closes the dialog.
2493 icon String A CSS class that provides a background image to be used as an icon for
2494 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2495 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2496 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2497 modal Boolean False to allow user interaction with the page while the message box is
2498 displayed (defaults to true)
2499 msg String A string that will replace the existing message box body text (defaults
2500 to the XHTML-compliant non-breaking space character ' ')
2501 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2502 progress Boolean True to display a progress bar (defaults to false)
2503 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2504 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2505 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2506 title String The title text
2507 value String The string value to set into the active textbox element if displayed
2508 wait Boolean True to display a progress bar (defaults to false)
2509 width Number The width of the dialog in pixels
2516 msg: 'Please enter your address:',
2518 buttons: Roo.MessageBox.OKCANCEL,
2521 animEl: 'addAddressBtn'
2524 * @param {Object} config Configuration options
2525 * @return {Roo.MessageBox} This message box
2527 show : function(options)
2530 // this causes nightmares if you show one dialog after another
2531 // especially on callbacks..
2533 if(this.isVisible()){
2536 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2537 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2538 Roo.log("New Dialog Message:" + options.msg )
2539 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2540 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2543 var d = this.getDialog();
2545 d.setTitle(opt.title || " ");
2546 d.close.setDisplayed(opt.closable !== false);
2547 activeTextEl = textboxEl;
2548 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2553 textareaEl.setHeight(typeof opt.multiline == "number" ?
2554 opt.multiline : this.defaultTextHeight);
2555 activeTextEl = textareaEl;
2564 progressEl.setDisplayed(opt.progress === true);
2565 this.updateProgress(0);
2566 activeTextEl.dom.value = opt.value || "";
2568 dlg.setDefaultButton(activeTextEl);
2570 var bs = opt.buttons;
2574 }else if(bs && bs.yes){
2575 db = buttons["yes"];
2577 dlg.setDefaultButton(db);
2579 bwidth = updateButtons(opt.buttons);
2580 this.updateText(opt.msg);
2582 d.el.addClass(opt.cls);
2584 d.proxyDrag = opt.proxyDrag === true;
2585 d.modal = opt.modal !== false;
2586 d.mask = opt.modal !== false ? mask : false;
2588 // force it to the end of the z-index stack so it gets a cursor in FF
2589 document.body.appendChild(dlg.el.dom);
2590 d.animateTarget = null;
2591 d.show(options.animEl);
2597 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2598 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2599 * and closing the message box when the process is complete.
2600 * @param {String} title The title bar text
2601 * @param {String} msg The message box body text
2602 * @return {Roo.MessageBox} This message box
2604 progress : function(title, msg){
2611 minWidth: this.minProgressWidth,
2618 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2619 * If a callback function is passed it will be called after the user clicks the button, and the
2620 * id of the button that was clicked will be passed as the only parameter to the callback
2621 * (could also be the top-right close button).
2622 * @param {String} title The title bar text
2623 * @param {String} msg The message box body text
2624 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2625 * @param {Object} scope (optional) The scope of the callback function
2626 * @return {Roo.MessageBox} This message box
2628 alert : function(title, msg, fn, scope){
2641 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2642 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2643 * You are responsible for closing the message box when the process is complete.
2644 * @param {String} msg The message box body text
2645 * @param {String} title (optional) The title bar text
2646 * @return {Roo.MessageBox} This message box
2648 wait : function(msg, title){
2659 waitTimer = Roo.TaskMgr.start({
2661 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2669 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2670 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2671 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2672 * @param {String} title The title bar text
2673 * @param {String} msg The message box body text
2674 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2675 * @param {Object} scope (optional) The scope of the callback function
2676 * @return {Roo.MessageBox} This message box
2678 confirm : function(title, msg, fn, scope){
2682 buttons: this.YESNO,
2691 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2692 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2693 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2694 * (could also be the top-right close button) and the text that was entered will be passed as the two
2695 * parameters to the callback.
2696 * @param {String} title The title bar text
2697 * @param {String} msg The message box body text
2698 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2699 * @param {Object} scope (optional) The scope of the callback function
2700 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2701 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2702 * @return {Roo.MessageBox} This message box
2704 prompt : function(title, msg, fn, scope, multiline){
2708 buttons: this.OKCANCEL,
2713 multiline: multiline,
2720 * Button config that displays a single OK button
2725 * Button config that displays Yes and No buttons
2728 YESNO : {yes:true, no:true},
2730 * Button config that displays OK and Cancel buttons
2733 OKCANCEL : {ok:true, cancel:true},
2735 * Button config that displays Yes, No and Cancel buttons
2738 YESNOCANCEL : {yes:true, no:true, cancel:true},
2741 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2744 defaultTextHeight : 75,
2746 * The maximum width in pixels of the message box (defaults to 600)
2751 * The minimum width in pixels of the message box (defaults to 100)
2756 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2757 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2760 minProgressWidth : 250,
2762 * An object containing the default button text strings that can be overriden for localized language support.
2763 * Supported properties are: ok, cancel, yes and no.
2764 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2777 * Shorthand for {@link Roo.MessageBox}
2779 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2780 Roo.Msg = Roo.Msg || Roo.MessageBox;
2789 * @class Roo.bootstrap.Navbar
2790 * @extends Roo.bootstrap.Component
2791 * Bootstrap Navbar class
2794 * Create a new Navbar
2795 * @param {Object} config The config object
2799 Roo.bootstrap.Navbar = function(config){
2800 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2804 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2813 getAutoCreate : function(){
2816 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
2820 initEvents :function ()
2822 //Roo.log(this.el.select('.navbar-toggle',true));
2823 this.el.select('.navbar-toggle',true).on('click', function() {
2824 // Roo.log('click');
2825 this.el.select('.navbar-collapse',true).toggleClass('in');
2833 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2835 var size = this.el.getSize();
2836 this.maskEl.setSize(size.width, size.height);
2837 this.maskEl.enableDisplayMode("block");
2846 getChildContainer : function()
2848 if (this.el.select('.collapse').getCount()) {
2849 return this.el.select('.collapse',true).first();
2882 * @class Roo.bootstrap.NavSimplebar
2883 * @extends Roo.bootstrap.Navbar
2884 * Bootstrap Sidebar class
2886 * @cfg {Boolean} inverse is inverted color
2888 * @cfg {String} type (nav | pills | tabs)
2889 * @cfg {Boolean} arrangement stacked | justified
2890 * @cfg {String} align (left | right) alignment
2892 * @cfg {Boolean} main (true|false) main nav bar? default false
2893 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
2895 * @cfg {String} tag (header|footer|nav|div) default is nav
2901 * Create a new Sidebar
2902 * @param {Object} config The config object
2906 Roo.bootstrap.NavSimplebar = function(config){
2907 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
2910 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
2926 getAutoCreate : function(){
2930 tag : this.tag || 'div',
2943 this.type = this.type || 'nav';
2944 if (['tabs','pills'].indexOf(this.type)!==-1) {
2945 cfg.cn[0].cls += ' nav-' + this.type
2949 if (this.type!=='nav') {
2950 Roo.log('nav type must be nav/tabs/pills')
2952 cfg.cn[0].cls += ' navbar-nav'
2958 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
2959 cfg.cn[0].cls += ' nav-' + this.arrangement;
2963 if (this.align === 'right') {
2964 cfg.cn[0].cls += ' navbar-right';
2968 cfg.cls += ' navbar-inverse';
2995 * @class Roo.bootstrap.NavHeaderbar
2996 * @extends Roo.bootstrap.NavSimplebar
2997 * Bootstrap Sidebar class
2999 * @cfg {String} brand what is brand
3000 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3001 * @cfg {String} brand_href href of the brand
3002 * @cfg {Boolean} srButton generate the sr-only button (true | false) default true
3005 * Create a new Sidebar
3006 * @param {Object} config The config object
3010 Roo.bootstrap.NavHeaderbar = function(config){
3011 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3014 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3022 getAutoCreate : function(){
3025 tag: this.nav || 'nav',
3034 cls: 'navbar-header',
3039 cls: 'navbar-toggle',
3040 'data-toggle': 'collapse',
3045 html: 'Toggle navigation'
3067 cls: 'collapse navbar-collapse',
3071 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3073 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3074 cfg.cls += ' navbar-' + this.position;
3076 // tag can override this..
3078 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3081 if (this.brand !== '') {
3084 href: this.brand_href ? this.brand_href : '#',
3085 cls: 'navbar-brand',
3093 cfg.cls += ' main-nav';
3118 * @class Roo.bootstrap.NavSidebar
3119 * @extends Roo.bootstrap.Navbar
3120 * Bootstrap Sidebar class
3123 * Create a new Sidebar
3124 * @param {Object} config The config object
3128 Roo.bootstrap.NavSidebar = function(config){
3129 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3132 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3134 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3136 getAutoCreate : function(){
3141 cls: 'sidebar sidebar-nav'
3163 * @class Roo.bootstrap.NavGroup
3164 * @extends Roo.bootstrap.Component
3165 * Bootstrap NavGroup class
3166 * @cfg {String} align left | right
3167 * @cfg {Boolean} inverse false | true
3168 * @cfg {String} type (nav|pills|tab) default nav
3169 * @cfg {String} navId - reference Id for navbar.
3173 * Create a new nav group
3174 * @param {Object} config The config object
3177 Roo.bootstrap.NavGroup = function(config){
3178 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3180 Roo.bootstrap.NavGroup.register(this);
3184 * Fires when the active item changes
3185 * @param {Roo.bootstrap.NavGroup} this
3186 * @param {Roo.bootstrap.Navbar.Item} item The item selected
3187 * @param {Roo.bootstrap.Navbar.Item} item The previously selected item
3194 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3205 getAutoCreate : function()
3207 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3214 if (['tabs','pills'].indexOf(this.type)!==-1) {
3215 cfg.cls += ' nav-' + this.type
3217 if (this.type!=='nav') {
3218 Roo.log('nav type must be nav/tabs/pills')
3220 cfg.cls += ' navbar-nav'
3223 if (this.parent().sidebar) {
3226 cls: 'dashboard-menu sidebar-menu'
3232 if (this.form === true) {
3238 if (this.align === 'right') {
3239 cfg.cls += ' navbar-right';
3241 cfg.cls += ' navbar-left';
3245 if (this.align === 'right') {
3246 cfg.cls += ' navbar-right';
3250 cfg.cls += ' navbar-inverse';
3258 setActiveItem : function(item)
3261 Roo.each(this.navItems, function(v){
3266 v.setActive(false, true);
3273 item.setActive(true, true);
3274 this.fireEvent('changed', this, item, prev);
3279 addItem : function(cfg)
3281 var cn = new Roo.bootstrap.NavItem(cfg);
3283 cn.parentId = this.id;
3284 cn.onRender(this.el, null);
3288 register : function(item)
3290 this.navItems.push( item);
3291 item.navId = this.navId;
3294 getNavItem: function(tabId)
3297 Roo.each(this.navItems, function(e) {
3298 if (e.tabId == tabId) {
3314 Roo.apply(Roo.bootstrap.NavGroup, {
3318 register : function(navgrp)
3320 this.groups[navgrp.navId] = navgrp;
3323 get: function(navId) {
3324 return this.groups[navId];
3339 * @class Roo.bootstrap.NavItem
3340 * @extends Roo.bootstrap.Component
3341 * Bootstrap Navbar.NavItem class
3342 * @cfg {String} href link to
3343 * @cfg {String} html content of button
3344 * @cfg {String} badge text inside badge
3345 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3346 * @cfg {String} glyphicon name of glyphicon
3347 * @cfg {String} icon name of font awesome icon
3348 * @cfg {Boolean} active Is item active
3349 * @cfg {Boolean} disabled Is item disabled
3351 * @cfg {Boolean} preventDefault (true | false) default false
3352 * @cfg {String} tabId the tab that this item activates.
3353 * @cfg {String} tagtype (a|span) render as a href or span?
3356 * Create a new Navbar Item
3357 * @param {Object} config The config object
3359 Roo.bootstrap.NavItem = function(config){
3360 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3365 * The raw click event for the entire grid.
3366 * @param {Roo.EventObject} e
3371 * Fires when the active item active state changes
3372 * @param {Roo.bootstrap.NavItem} this
3373 * @param {boolean} state the new state
3381 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3389 preventDefault : false,
3394 getAutoCreate : function(){
3402 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3404 if (this.disabled) {
3405 cfg.cls += ' disabled';
3408 if (this.href || this.html || this.glyphicon || this.icon) {
3412 href : this.href || "#",
3413 html: this.html || ''
3418 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3421 if(this.glyphicon) {
3422 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3427 cfg.cn[0].html += " <span class='caret'></span>";
3431 if (this.badge !== '') {
3433 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3441 initEvents: function() {
3442 // Roo.log('init events?');
3443 // Roo.log(this.el.dom);
3444 if (typeof (this.menu) != 'undefined') {
3445 this.menu.parentType = this.xtype;
3446 this.menu.triggerEl = this.el;
3447 this.addxtype(Roo.apply({}, this.menu));
3451 this.el.select('a',true).on('click', this.onClick, this);
3452 // at this point parent should be available..
3453 this.parent().register(this);
3456 onClick : function(e)
3459 if(this.preventDefault){
3462 if (this.disabled) {
3465 Roo.log("fire event clicked");
3466 if(this.fireEvent('click', this, e) === false){
3470 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3471 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3472 this.parent().setActiveItem(this);
3480 isActive: function () {
3483 setActive : function(state, fire)
3485 this.active = state;
3487 this.el.removeClass('active');
3488 } else if (!this.el.hasClass('active')) {
3489 this.el.addClass('active');
3492 this.fireEvent('changed', this, state);
3497 // this should not be here...
3498 setDisabled : function(state)
3500 this.disabled = state;
3502 this.el.removeClass('disabled');
3503 } else if (!this.el.hasClass('disabled')) {
3504 this.el.addClass('disabled');
3517 * <span> icon </span>
3518 * <span> text </span>
3519 * <span>badge </span>
3523 * @class Roo.bootstrap.NavSidebarItem
3524 * @extends Roo.bootstrap.NavItem
3525 * Bootstrap Navbar.NavSidebarItem class
3527 * Create a new Navbar Button
3528 * @param {Object} config The config object
3530 Roo.bootstrap.NavSidebarItem = function(config){
3531 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3536 * The raw click event for the entire grid.
3537 * @param {Roo.EventObject} e
3542 * Fires when the active item active state changes
3543 * @param {Roo.bootstrap.NavSidebarItem} this
3544 * @param {boolean} state the new state
3552 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3555 getAutoCreate : function(){
3560 href : this.href || '#',
3572 html : this.html || ''
3577 cfg.cls += ' active';
3581 if (this.glyphicon || this.icon) {
3582 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3583 a.cn.push({ tag : 'i', cls : c }) ;
3588 if (this.badge !== '') {
3589 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3593 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3594 a.cls += 'dropdown-toggle treeview' ;
3618 * @class Roo.bootstrap.Row
3619 * @extends Roo.bootstrap.Component
3620 * Bootstrap Row class (contains columns...)
3624 * @param {Object} config The config object
3627 Roo.bootstrap.Row = function(config){
3628 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3631 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3633 getAutoCreate : function(){
3652 * @class Roo.bootstrap.Element
3653 * @extends Roo.bootstrap.Component
3654 * Bootstrap Element class
3655 * @cfg {String} html contents of the element
3656 * @cfg {String} tag tag of the element
3657 * @cfg {String} cls class of the element
3660 * Create a new Element
3661 * @param {Object} config The config object
3664 Roo.bootstrap.Element = function(config){
3665 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3668 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3675 getAutoCreate : function(){
3700 * @class Roo.bootstrap.Pagination
3701 * @extends Roo.bootstrap.Component
3702 * Bootstrap Pagination class
3703 * @cfg {String} size xs | sm | md | lg
3704 * @cfg {Boolean} inverse false | true
3707 * Create a new Pagination
3708 * @param {Object} config The config object
3711 Roo.bootstrap.Pagination = function(config){
3712 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3715 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3721 getAutoCreate : function(){
3727 cfg.cls += ' inverse';
3733 cfg.cls += " " + this.cls;
3751 * @class Roo.bootstrap.PaginationItem
3752 * @extends Roo.bootstrap.Component
3753 * Bootstrap PaginationItem class
3754 * @cfg {String} html text
3755 * @cfg {String} href the link
3756 * @cfg {Boolean} preventDefault (true | false) default true
3757 * @cfg {Boolean} active (true | false) default false
3761 * Create a new PaginationItem
3762 * @param {Object} config The config object
3766 Roo.bootstrap.PaginationItem = function(config){
3767 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3772 * The raw click event for the entire grid.
3773 * @param {Roo.EventObject} e
3779 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
3783 preventDefault: true,
3787 getAutoCreate : function(){
3793 href : this.href ? this.href : '#',
3794 html : this.html ? this.html : ''
3804 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
3810 initEvents: function() {
3812 this.el.on('click', this.onClick, this);
3815 onClick : function(e)
3817 Roo.log('PaginationItem on click ');
3818 if(this.preventDefault){
3822 this.fireEvent('click', this, e);
3838 * @class Roo.bootstrap.Slider
3839 * @extends Roo.bootstrap.Component
3840 * Bootstrap Slider class
3843 * Create a new Slider
3844 * @param {Object} config The config object
3847 Roo.bootstrap.Slider = function(config){
3848 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
3851 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
3853 getAutoCreate : function(){
3857 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
3861 cls: 'ui-slider-handle ui-state-default ui-corner-all'
3873 * Ext JS Library 1.1.1
3874 * Copyright(c) 2006-2007, Ext JS, LLC.
3876 * Originally Released Under LGPL - original licence link has changed is not relivant.
3879 * <script type="text/javascript">
3884 * @class Roo.grid.ColumnModel
3885 * @extends Roo.util.Observable
3886 * This is the default implementation of a ColumnModel used by the Grid. It defines
3887 * the columns in the grid.
3890 var colModel = new Roo.grid.ColumnModel([
3891 {header: "Ticker", width: 60, sortable: true, locked: true},
3892 {header: "Company Name", width: 150, sortable: true},
3893 {header: "Market Cap.", width: 100, sortable: true},
3894 {header: "$ Sales", width: 100, sortable: true, renderer: money},
3895 {header: "Employees", width: 100, sortable: true, resizable: false}
3900 * The config options listed for this class are options which may appear in each
3901 * individual column definition.
3902 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
3904 * @param {Object} config An Array of column config objects. See this class's
3905 * config objects for details.
3907 Roo.grid.ColumnModel = function(config){
3909 * The config passed into the constructor
3911 this.config = config;
3914 // if no id, create one
3915 // if the column does not have a dataIndex mapping,
3916 // map it to the order it is in the config
3917 for(var i = 0, len = config.length; i < len; i++){
3919 if(typeof c.dataIndex == "undefined"){
3922 if(typeof c.renderer == "string"){
3923 c.renderer = Roo.util.Format[c.renderer];
3925 if(typeof c.id == "undefined"){
3928 if(c.editor && c.editor.xtype){
3929 c.editor = Roo.factory(c.editor, Roo.grid);
3931 if(c.editor && c.editor.isFormField){
3932 c.editor = new Roo.grid.GridEditor(c.editor);
3934 this.lookup[c.id] = c;
3938 * The width of columns which have no width specified (defaults to 100)
3941 this.defaultWidth = 100;
3944 * Default sortable of columns which have no sortable specified (defaults to false)
3947 this.defaultSortable = false;
3951 * @event widthchange
3952 * Fires when the width of a column changes.
3953 * @param {ColumnModel} this
3954 * @param {Number} columnIndex The column index
3955 * @param {Number} newWidth The new width
3957 "widthchange": true,
3959 * @event headerchange
3960 * Fires when the text of a header changes.
3961 * @param {ColumnModel} this
3962 * @param {Number} columnIndex The column index
3963 * @param {Number} newText The new header text
3965 "headerchange": true,
3967 * @event hiddenchange
3968 * Fires when a column is hidden or "unhidden".
3969 * @param {ColumnModel} this
3970 * @param {Number} columnIndex The column index
3971 * @param {Boolean} hidden true if hidden, false otherwise
3973 "hiddenchange": true,
3975 * @event columnmoved
3976 * Fires when a column is moved.
3977 * @param {ColumnModel} this
3978 * @param {Number} oldIndex
3979 * @param {Number} newIndex
3981 "columnmoved" : true,
3983 * @event columlockchange
3984 * Fires when a column's locked state is changed
3985 * @param {ColumnModel} this
3986 * @param {Number} colIndex
3987 * @param {Boolean} locked true if locked
3989 "columnlockchange" : true
3991 Roo.grid.ColumnModel.superclass.constructor.call(this);
3993 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
3995 * @cfg {String} header The header text to display in the Grid view.
3998 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
3999 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4000 * specified, the column's index is used as an index into the Record's data Array.
4003 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4004 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4007 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4008 * Defaults to the value of the {@link #defaultSortable} property.
4009 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4012 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4015 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4018 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4021 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4024 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4025 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4026 * default renderer uses the raw data value.
4029 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4032 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4036 * Returns the id of the column at the specified index.
4037 * @param {Number} index The column index
4038 * @return {String} the id
4040 getColumnId : function(index){
4041 return this.config[index].id;
4045 * Returns the column for a specified id.
4046 * @param {String} id The column id
4047 * @return {Object} the column
4049 getColumnById : function(id){
4050 return this.lookup[id];
4055 * Returns the column for a specified dataIndex.
4056 * @param {String} dataIndex The column dataIndex
4057 * @return {Object|Boolean} the column or false if not found
4059 getColumnByDataIndex: function(dataIndex){
4060 var index = this.findColumnIndex(dataIndex);
4061 return index > -1 ? this.config[index] : false;
4065 * Returns the index for a specified column id.
4066 * @param {String} id The column id
4067 * @return {Number} the index, or -1 if not found
4069 getIndexById : function(id){
4070 for(var i = 0, len = this.config.length; i < len; i++){
4071 if(this.config[i].id == id){
4079 * Returns the index for a specified column dataIndex.
4080 * @param {String} dataIndex The column dataIndex
4081 * @return {Number} the index, or -1 if not found
4084 findColumnIndex : function(dataIndex){
4085 for(var i = 0, len = this.config.length; i < len; i++){
4086 if(this.config[i].dataIndex == dataIndex){
4094 moveColumn : function(oldIndex, newIndex){
4095 var c = this.config[oldIndex];
4096 this.config.splice(oldIndex, 1);
4097 this.config.splice(newIndex, 0, c);
4098 this.dataMap = null;
4099 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4102 isLocked : function(colIndex){
4103 return this.config[colIndex].locked === true;
4106 setLocked : function(colIndex, value, suppressEvent){
4107 if(this.isLocked(colIndex) == value){
4110 this.config[colIndex].locked = value;
4112 this.fireEvent("columnlockchange", this, colIndex, value);
4116 getTotalLockedWidth : function(){
4118 for(var i = 0; i < this.config.length; i++){
4119 if(this.isLocked(i) && !this.isHidden(i)){
4120 this.totalWidth += this.getColumnWidth(i);
4126 getLockedCount : function(){
4127 for(var i = 0, len = this.config.length; i < len; i++){
4128 if(!this.isLocked(i)){
4135 * Returns the number of columns.
4138 getColumnCount : function(visibleOnly){
4139 if(visibleOnly === true){
4141 for(var i = 0, len = this.config.length; i < len; i++){
4142 if(!this.isHidden(i)){
4148 return this.config.length;
4152 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4153 * @param {Function} fn
4154 * @param {Object} scope (optional)
4155 * @return {Array} result
4157 getColumnsBy : function(fn, scope){
4159 for(var i = 0, len = this.config.length; i < len; i++){
4160 var c = this.config[i];
4161 if(fn.call(scope||this, c, i) === true){
4169 * Returns true if the specified column is sortable.
4170 * @param {Number} col The column index
4173 isSortable : function(col){
4174 if(typeof this.config[col].sortable == "undefined"){
4175 return this.defaultSortable;
4177 return this.config[col].sortable;
4181 * Returns the rendering (formatting) function defined for the column.
4182 * @param {Number} col The column index.
4183 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4185 getRenderer : function(col){
4186 if(!this.config[col].renderer){
4187 return Roo.grid.ColumnModel.defaultRenderer;
4189 return this.config[col].renderer;
4193 * Sets the rendering (formatting) function for a column.
4194 * @param {Number} col The column index
4195 * @param {Function} fn The function to use to process the cell's raw data
4196 * to return HTML markup for the grid view. The render function is called with
4197 * the following parameters:<ul>
4198 * <li>Data value.</li>
4199 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4200 * <li>css A CSS style string to apply to the table cell.</li>
4201 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4202 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4203 * <li>Row index</li>
4204 * <li>Column index</li>
4205 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4207 setRenderer : function(col, fn){
4208 this.config[col].renderer = fn;
4212 * Returns the width for the specified column.
4213 * @param {Number} col The column index
4216 getColumnWidth : function(col){
4217 return this.config[col].width * 1 || this.defaultWidth;
4221 * Sets the width for a column.
4222 * @param {Number} col The column index
4223 * @param {Number} width The new width
4225 setColumnWidth : function(col, width, suppressEvent){
4226 this.config[col].width = width;
4227 this.totalWidth = null;
4229 this.fireEvent("widthchange", this, col, width);
4234 * Returns the total width of all columns.
4235 * @param {Boolean} includeHidden True to include hidden column widths
4238 getTotalWidth : function(includeHidden){
4239 if(!this.totalWidth){
4240 this.totalWidth = 0;
4241 for(var i = 0, len = this.config.length; i < len; i++){
4242 if(includeHidden || !this.isHidden(i)){
4243 this.totalWidth += this.getColumnWidth(i);
4247 return this.totalWidth;
4251 * Returns the header for the specified column.
4252 * @param {Number} col The column index
4255 getColumnHeader : function(col){
4256 return this.config[col].header;
4260 * Sets the header for a column.
4261 * @param {Number} col The column index
4262 * @param {String} header The new header
4264 setColumnHeader : function(col, header){
4265 this.config[col].header = header;
4266 this.fireEvent("headerchange", this, col, header);
4270 * Returns the tooltip for the specified column.
4271 * @param {Number} col The column index
4274 getColumnTooltip : function(col){
4275 return this.config[col].tooltip;
4278 * Sets the tooltip for a column.
4279 * @param {Number} col The column index
4280 * @param {String} tooltip The new tooltip
4282 setColumnTooltip : function(col, tooltip){
4283 this.config[col].tooltip = tooltip;
4287 * Returns the dataIndex for the specified column.
4288 * @param {Number} col The column index
4291 getDataIndex : function(col){
4292 return this.config[col].dataIndex;
4296 * Sets the dataIndex for a column.
4297 * @param {Number} col The column index
4298 * @param {Number} dataIndex The new dataIndex
4300 setDataIndex : function(col, dataIndex){
4301 this.config[col].dataIndex = dataIndex;
4307 * Returns true if the cell is editable.
4308 * @param {Number} colIndex The column index
4309 * @param {Number} rowIndex The row index
4312 isCellEditable : function(colIndex, rowIndex){
4313 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4317 * Returns the editor defined for the cell/column.
4318 * return false or null to disable editing.
4319 * @param {Number} colIndex The column index
4320 * @param {Number} rowIndex The row index
4323 getCellEditor : function(colIndex, rowIndex){
4324 return this.config[colIndex].editor;
4328 * Sets if a column is editable.
4329 * @param {Number} col The column index
4330 * @param {Boolean} editable True if the column is editable
4332 setEditable : function(col, editable){
4333 this.config[col].editable = editable;
4338 * Returns true if the column is hidden.
4339 * @param {Number} colIndex The column index
4342 isHidden : function(colIndex){
4343 return this.config[colIndex].hidden;
4348 * Returns true if the column width cannot be changed
4350 isFixed : function(colIndex){
4351 return this.config[colIndex].fixed;
4355 * Returns true if the column can be resized
4358 isResizable : function(colIndex){
4359 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4362 * Sets if a column is hidden.
4363 * @param {Number} colIndex The column index
4364 * @param {Boolean} hidden True if the column is hidden
4366 setHidden : function(colIndex, hidden){
4367 this.config[colIndex].hidden = hidden;
4368 this.totalWidth = null;
4369 this.fireEvent("hiddenchange", this, colIndex, hidden);
4373 * Sets the editor for a column.
4374 * @param {Number} col The column index
4375 * @param {Object} editor The editor object
4377 setEditor : function(col, editor){
4378 this.config[col].editor = editor;
4382 Roo.grid.ColumnModel.defaultRenderer = function(value){
4383 if(typeof value == "string" && value.length < 1){
4389 // Alias for backwards compatibility
4390 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4393 * Ext JS Library 1.1.1
4394 * Copyright(c) 2006-2007, Ext JS, LLC.
4396 * Originally Released Under LGPL - original licence link has changed is not relivant.
4399 * <script type="text/javascript">
4403 * @class Roo.LoadMask
4404 * A simple utility class for generically masking elements while loading data. If the element being masked has
4405 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4406 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4407 * element's UpdateManager load indicator and will be destroyed after the initial load.
4409 * Create a new LoadMask
4410 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4411 * @param {Object} config The config object
4413 Roo.LoadMask = function(el, config){
4414 this.el = Roo.get(el);
4415 Roo.apply(this, config);
4417 this.store.on('beforeload', this.onBeforeLoad, this);
4418 this.store.on('load', this.onLoad, this);
4419 this.store.on('loadexception', this.onLoadException, this);
4420 this.removeMask = false;
4422 var um = this.el.getUpdateManager();
4423 um.showLoadIndicator = false; // disable the default indicator
4424 um.on('beforeupdate', this.onBeforeLoad, this);
4425 um.on('update', this.onLoad, this);
4426 um.on('failure', this.onLoad, this);
4427 this.removeMask = true;
4431 Roo.LoadMask.prototype = {
4433 * @cfg {Boolean} removeMask
4434 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4435 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4439 * The text to display in a centered loading message box (defaults to 'Loading...')
4443 * @cfg {String} msgCls
4444 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4446 msgCls : 'x-mask-loading',
4449 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4455 * Disables the mask to prevent it from being displayed
4457 disable : function(){
4458 this.disabled = true;
4462 * Enables the mask so that it can be displayed
4464 enable : function(){
4465 this.disabled = false;
4468 onLoadException : function()
4472 if (typeof(arguments[3]) != 'undefined') {
4473 Roo.MessageBox.alert("Error loading",arguments[3]);
4477 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4478 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4487 this.el.unmask(this.removeMask);
4492 this.el.unmask(this.removeMask);
4496 onBeforeLoad : function(){
4498 this.el.mask(this.msg, this.msgCls);
4503 destroy : function(){
4505 this.store.un('beforeload', this.onBeforeLoad, this);
4506 this.store.un('load', this.onLoad, this);
4507 this.store.un('loadexception', this.onLoadException, this);
4509 var um = this.el.getUpdateManager();
4510 um.un('beforeupdate', this.onBeforeLoad, this);
4511 um.un('update', this.onLoad, this);
4512 um.un('failure', this.onLoad, this);
4523 * @class Roo.bootstrap.Table
4524 * @extends Roo.bootstrap.Component
4525 * Bootstrap Table class
4526 * @cfg {String} cls table class
4527 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4528 * @cfg {String} bgcolor Specifies the background color for a table
4529 * @cfg {Number} border Specifies whether the table cells should have borders or not
4530 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4531 * @cfg {Number} cellspacing Specifies the space between cells
4532 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4533 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4534 * @cfg {String} sortable Specifies that the table should be sortable
4535 * @cfg {String} summary Specifies a summary of the content of a table
4536 * @cfg {Number} width Specifies the width of a table
4537 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4539 * @cfg {boolean} striped Should the rows be alternative striped
4540 * @cfg {boolean} bordered Add borders to the table
4541 * @cfg {boolean} hover Add hover highlighting
4542 * @cfg {boolean} condensed Format condensed
4543 * @cfg {boolean} responsive Format condensed
4544 * @cfg {Boolean} loadMask (true|false) default false
4545 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4546 * @cfg {Boolean} thead (true|false) generate thead, default true
4547 * @cfg {Boolean} RowSelection (true|false) default false
4548 * @cfg {Boolean} CellSelection (true|false) default false
4550 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4554 * Create a new Table
4555 * @param {Object} config The config object
4558 Roo.bootstrap.Table = function(config){
4559 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4562 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4563 this.sm = this.selModel;
4564 this.sm.xmodule = this.xmodule || false;
4566 if (this.cm && typeof(this.cm.config) == 'undefined') {
4567 this.colModel = new Roo.grid.ColumnModel(this.cm);
4568 this.cm = this.colModel;
4569 this.cm.xmodule = this.xmodule || false;
4572 this.store= Roo.factory(this.store, Roo.data);
4573 this.ds = this.store;
4574 this.ds.xmodule = this.xmodule || false;
4577 if (this.footer && this.store) {
4578 this.footer.dataSource = this.ds;
4579 this.footer = Roo.factory(this.footer);
4586 * Fires when a cell is clicked
4587 * @param {Roo.bootstrap.Table} this
4588 * @param {Roo.Element} el
4589 * @param {Number} rowIndex
4590 * @param {Number} columnIndex
4591 * @param {Roo.EventObject} e
4595 * @event celldblclick
4596 * Fires when a cell is double clicked
4597 * @param {Roo.bootstrap.Table} this
4598 * @param {Roo.Element} el
4599 * @param {Number} rowIndex
4600 * @param {Number} columnIndex
4601 * @param {Roo.EventObject} e
4603 "celldblclick" : true,
4606 * Fires when a row is clicked
4607 * @param {Roo.bootstrap.Table} this
4608 * @param {Roo.Element} el
4609 * @param {Number} rowIndex
4610 * @param {Roo.EventObject} e
4614 * @event rowdblclick
4615 * Fires when a row is double clicked
4616 * @param {Roo.bootstrap.Table} this
4617 * @param {Roo.Element} el
4618 * @param {Number} rowIndex
4619 * @param {Roo.EventObject} e
4621 "rowdblclick" : true,
4624 * Fires when a mouseover occur
4625 * @param {Roo.bootstrap.Table} this
4626 * @param {Roo.Element} el
4627 * @param {Number} rowIndex
4628 * @param {Number} columnIndex
4629 * @param {Roo.EventObject} e
4634 * Fires when a mouseout occur
4635 * @param {Roo.bootstrap.Table} this
4636 * @param {Roo.Element} el
4637 * @param {Number} rowIndex
4638 * @param {Number} columnIndex
4639 * @param {Roo.EventObject} e
4644 * Fires when a row is rendered, so you can change add a style to it.
4645 * @param {Roo.bootstrap.Table} this
4646 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
4651 * Fires when record have been loaded
4652 * @param {Roo.bootstrap.Table} this
4653 * @param {Object} records store records
4660 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4684 RowSelection : false,
4685 CellSelection : false,
4689 getAutoCreate : function(){
4690 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4699 cfg.cls += ' table-striped';
4703 cfg.cls += ' table-hover';
4705 if (this.bordered) {
4706 cfg.cls += ' table-bordered';
4708 if (this.condensed) {
4709 cfg.cls += ' table-condensed';
4711 if (this.responsive) {
4712 cfg.cls += ' table-responsive';
4716 cfg.cls+= ' ' +this.cls;
4719 // this lot should be simplifed...
4722 cfg.align=this.align;
4725 cfg.bgcolor=this.bgcolor;
4728 cfg.border=this.border;
4730 if (this.cellpadding) {
4731 cfg.cellpadding=this.cellpadding;
4733 if (this.cellspacing) {
4734 cfg.cellspacing=this.cellspacing;
4737 cfg.frame=this.frame;
4740 cfg.rules=this.rules;
4742 if (this.sortable) {
4743 cfg.sortable=this.sortable;
4746 cfg.summary=this.summary;
4749 cfg.width=this.width;
4752 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
4755 if(this.store || this.cm){
4757 cfg.cn.push(this.renderHeader());
4760 cfg.cn.push(this.renderBody());
4763 cfg.cn.push(this.renderFooter());
4766 cfg.cls+= ' TableGrid';
4769 return { cn : [ cfg ] };
4772 initEvents : function()
4774 if(!this.store || !this.cm){
4778 Roo.log('initEvents with ds!!!!');
4782 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4783 e.on('click', _this.sort, _this);
4786 this.el.on("click", this.onClick, this);
4787 this.el.on("dblclick", this.onDblClick, this);
4789 this.parent().el.setStyle('position', 'relative');
4791 this.footer.parentId = this.id;
4792 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
4795 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
4797 this.store.on('load', this.onLoad, this);
4798 this.store.on('beforeload', this.onBeforeLoad, this);
4802 onMouseover : function(e, el)
4804 var cell = Roo.get(el);
4810 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4811 cell = cell.findParent('td', false, true);
4814 var row = cell.findParent('tr', false, true);
4815 var cellIndex = cell.dom.cellIndex;
4816 var rowIndex = row.dom.rowIndex - 1; // start from 0
4818 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
4822 onMouseout : function(e, el)
4824 var cell = Roo.get(el);
4830 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4831 cell = cell.findParent('td', false, true);
4834 var row = cell.findParent('tr', false, true);
4835 var cellIndex = cell.dom.cellIndex;
4836 var rowIndex = row.dom.rowIndex - 1; // start from 0
4838 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
4842 onClick : function(e, el)
4844 var cell = Roo.get(el);
4846 if(!cell || !this.CellSelection || !this.RowSelection){
4851 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4852 cell = cell.findParent('td', false, true);
4855 var row = cell.findParent('tr', false, true);
4856 var cellIndex = cell.dom.cellIndex;
4857 var rowIndex = row.dom.rowIndex - 1;
4859 if(this.CellSelection){
4860 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
4863 if(this.RowSelection){
4864 this.fireEvent('rowclick', this, row, rowIndex, e);
4870 onDblClick : function(e,el)
4872 var cell = Roo.get(el);
4874 if(!cell || !this.CellSelection || !this.RowSelection){
4878 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4879 cell = cell.findParent('td', false, true);
4882 var row = cell.findParent('tr', false, true);
4883 var cellIndex = cell.dom.cellIndex;
4884 var rowIndex = row.dom.rowIndex - 1;
4886 if(this.CellSelection){
4887 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
4890 if(this.RowSelection){
4891 this.fireEvent('rowdblclick', this, row, rowIndex, e);
4895 sort : function(e,el)
4897 var col = Roo.get(el)
4899 if(!col.hasClass('sortable')){
4903 var sort = col.attr('sort');
4906 if(col.hasClass('glyphicon-arrow-up')){
4910 this.store.sortInfo = {field : sort, direction : dir};
4913 Roo.log("calling footer first");
4914 this.footer.onClick('first');
4917 this.store.load({ params : { start : 0 } });
4921 renderHeader : function()
4930 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4932 var config = cm.config[i];
4937 html: cm.getColumnHeader(i)
4940 if(typeof(config.hidden) != 'undefined' && config.hidden){
4941 c.style += ' display:none;';
4944 if(typeof(config.dataIndex) != 'undefined'){
4945 c.sort = config.dataIndex;
4948 if(typeof(config.sortable) != 'undefined' && config.sortable){
4952 // if(typeof(config.align) != 'undefined' && config.align.length){
4953 // c.style += ' text-align:' + config.align + ';';
4956 if(typeof(config.width) != 'undefined'){
4957 c.style += ' width:' + config.width + 'px;';
4966 renderBody : function()
4976 colspan : this.cm.getColumnCount()
4986 renderFooter : function()
4996 colspan : this.cm.getColumnCount()
5008 Roo.log('ds onload');
5014 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5015 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5017 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5018 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5021 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5022 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5026 var tbody = this.el.select('tbody', true).first();
5030 if(this.store.getCount() > 0){
5031 this.store.data.each(function(d,rowIndex){
5037 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5038 var config = cm.config[i];
5040 var renderer = cm.getRenderer(i);
5044 if(typeof(renderer) !== 'undefined'){
5045 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5048 if(typeof(value) === 'object'){
5057 rowIndex : rowIndex,
5062 _this.fireEvent('rowclass', this, rowcfg);
5067 cls : rowcfg.rowClass,
5069 html: (typeof(value) === 'object') ? '' : value
5072 if(typeof(config.hidden) != 'undefined' && config.hidden){
5073 td.style += ' display:none;';
5076 if(typeof(config.align) != 'undefined' && config.align.length){
5077 td.style += ' text-align:' + config.align + ';';
5080 if(typeof(config.width) != 'undefined'){
5081 td.style += ' width:' + config.width + 'px;';
5089 tbody.createChild(row);
5097 Roo.each(renders, function(r){
5098 _this.renderColumn(r);
5102 Roo.each(this.el.select('tbody td', true).elements, function(e){
5103 e.on('mouseover', _this.onMouseover, _this);
5106 Roo.each(this.el.select('tbody td', true).elements, function(e){
5107 e.on('mouseout', _this.onMouseout, _this);
5110 this.fireEvent('afterload', this, this.store.data);
5111 //if(this.loadMask){
5112 // this.maskEl.hide();
5116 onBeforeLoad : function()
5118 //Roo.log('ds onBeforeLoad');
5122 //if(this.loadMask){
5123 // this.maskEl.show();
5129 this.el.select('tbody', true).first().dom.innerHTML = '';
5132 getSelectionModel : function(){
5134 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5136 return this.selModel;
5139 renderColumn : function(r)
5143 var t = r.cfg.render(r.container);
5146 Roo.each(r.cfg.cn, function(c){
5148 container: t.getChildContainer(),
5151 _this.renderColumn(child);
5168 * @class Roo.bootstrap.TableCell
5169 * @extends Roo.bootstrap.Component
5170 * Bootstrap TableCell class
5171 * @cfg {String} html cell contain text
5172 * @cfg {String} cls cell class
5173 * @cfg {String} tag cell tag (td|th) default td
5174 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5175 * @cfg {String} align Aligns the content in a cell
5176 * @cfg {String} axis Categorizes cells
5177 * @cfg {String} bgcolor Specifies the background color of a cell
5178 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5179 * @cfg {Number} colspan Specifies the number of columns a cell should span
5180 * @cfg {String} headers Specifies one or more header cells a cell is related to
5181 * @cfg {Number} height Sets the height of a cell
5182 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5183 * @cfg {Number} rowspan Sets the number of rows a cell should span
5184 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5185 * @cfg {String} valign Vertical aligns the content in a cell
5186 * @cfg {Number} width Specifies the width of a cell
5189 * Create a new TableCell
5190 * @param {Object} config The config object
5193 Roo.bootstrap.TableCell = function(config){
5194 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5197 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5217 getAutoCreate : function(){
5218 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5238 cfg.align=this.align
5244 cfg.bgcolor=this.bgcolor
5247 cfg.charoff=this.charoff
5250 cfg.colspan=this.colspan
5253 cfg.headers=this.headers
5256 cfg.height=this.height
5259 cfg.nowrap=this.nowrap
5262 cfg.rowspan=this.rowspan
5265 cfg.scope=this.scope
5268 cfg.valign=this.valign
5271 cfg.width=this.width
5290 * @class Roo.bootstrap.TableRow
5291 * @extends Roo.bootstrap.Component
5292 * Bootstrap TableRow class
5293 * @cfg {String} cls row class
5294 * @cfg {String} align Aligns the content in a table row
5295 * @cfg {String} bgcolor Specifies a background color for a table row
5296 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5297 * @cfg {String} valign Vertical aligns the content in a table row
5300 * Create a new TableRow
5301 * @param {Object} config The config object
5304 Roo.bootstrap.TableRow = function(config){
5305 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5308 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5316 getAutoCreate : function(){
5317 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5327 cfg.align = this.align;
5330 cfg.bgcolor = this.bgcolor;
5333 cfg.charoff = this.charoff;
5336 cfg.valign = this.valign;
5354 * @class Roo.bootstrap.TableBody
5355 * @extends Roo.bootstrap.Component
5356 * Bootstrap TableBody class
5357 * @cfg {String} cls element class
5358 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5359 * @cfg {String} align Aligns the content inside the element
5360 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5361 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5364 * Create a new TableBody
5365 * @param {Object} config The config object
5368 Roo.bootstrap.TableBody = function(config){
5369 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5372 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5380 getAutoCreate : function(){
5381 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5395 cfg.align = this.align;
5398 cfg.charoff = this.charoff;
5401 cfg.valign = this.valign;
5408 // initEvents : function()
5415 // this.store = Roo.factory(this.store, Roo.data);
5416 // this.store.on('load', this.onLoad, this);
5418 // this.store.load();
5422 // onLoad: function ()
5424 // this.fireEvent('load', this);
5434 * Ext JS Library 1.1.1
5435 * Copyright(c) 2006-2007, Ext JS, LLC.
5437 * Originally Released Under LGPL - original licence link has changed is not relivant.
5440 * <script type="text/javascript">
5443 // as we use this in bootstrap.
5444 Roo.namespace('Roo.form');
5446 * @class Roo.form.Action
5447 * Internal Class used to handle form actions
5449 * @param {Roo.form.BasicForm} el The form element or its id
5450 * @param {Object} config Configuration options
5455 // define the action interface
5456 Roo.form.Action = function(form, options){
5458 this.options = options || {};
5461 * Client Validation Failed
5464 Roo.form.Action.CLIENT_INVALID = 'client';
5466 * Server Validation Failed
5469 Roo.form.Action.SERVER_INVALID = 'server';
5471 * Connect to Server Failed
5474 Roo.form.Action.CONNECT_FAILURE = 'connect';
5476 * Reading Data from Server Failed
5479 Roo.form.Action.LOAD_FAILURE = 'load';
5481 Roo.form.Action.prototype = {
5483 failureType : undefined,
5484 response : undefined,
5488 run : function(options){
5493 success : function(response){
5498 handleResponse : function(response){
5502 // default connection failure
5503 failure : function(response){
5505 this.response = response;
5506 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5507 this.form.afterAction(this, false);
5510 processResponse : function(response){
5511 this.response = response;
5512 if(!response.responseText){
5515 this.result = this.handleResponse(response);
5519 // utility functions used internally
5520 getUrl : function(appendParams){
5521 var url = this.options.url || this.form.url || this.form.el.dom.action;
5523 var p = this.getParams();
5525 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5531 getMethod : function(){
5532 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5535 getParams : function(){
5536 var bp = this.form.baseParams;
5537 var p = this.options.params;
5539 if(typeof p == "object"){
5540 p = Roo.urlEncode(Roo.applyIf(p, bp));
5541 }else if(typeof p == 'string' && bp){
5542 p += '&' + Roo.urlEncode(bp);
5545 p = Roo.urlEncode(bp);
5550 createCallback : function(){
5552 success: this.success,
5553 failure: this.failure,
5555 timeout: (this.form.timeout*1000),
5556 upload: this.form.fileUpload ? this.success : undefined
5561 Roo.form.Action.Submit = function(form, options){
5562 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
5565 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
5568 haveProgress : false,
5569 uploadComplete : false,
5571 // uploadProgress indicator.
5572 uploadProgress : function()
5574 if (!this.form.progressUrl) {
5578 if (!this.haveProgress) {
5579 Roo.MessageBox.progress("Uploading", "Uploading");
5581 if (this.uploadComplete) {
5582 Roo.MessageBox.hide();
5586 this.haveProgress = true;
5588 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
5590 var c = new Roo.data.Connection();
5592 url : this.form.progressUrl,
5597 success : function(req){
5598 //console.log(data);
5602 rdata = Roo.decode(req.responseText)
5604 Roo.log("Invalid data from server..");
5608 if (!rdata || !rdata.success) {
5610 Roo.MessageBox.alert(Roo.encode(rdata));
5613 var data = rdata.data;
5615 if (this.uploadComplete) {
5616 Roo.MessageBox.hide();
5621 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
5622 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
5625 this.uploadProgress.defer(2000,this);
5628 failure: function(data) {
5629 Roo.log('progress url failed ');
5640 // run get Values on the form, so it syncs any secondary forms.
5641 this.form.getValues();
5643 var o = this.options;
5644 var method = this.getMethod();
5645 var isPost = method == 'POST';
5646 if(o.clientValidation === false || this.form.isValid()){
5648 if (this.form.progressUrl) {
5649 this.form.findField('UPLOAD_IDENTIFIER').setValue(
5650 (new Date() * 1) + '' + Math.random());
5655 Roo.Ajax.request(Roo.apply(this.createCallback(), {
5656 form:this.form.el.dom,
5657 url:this.getUrl(!isPost),
5659 params:isPost ? this.getParams() : null,
5660 isUpload: this.form.fileUpload
5663 this.uploadProgress();
5665 }else if (o.clientValidation !== false){ // client validation failed
5666 this.failureType = Roo.form.Action.CLIENT_INVALID;
5667 this.form.afterAction(this, false);
5671 success : function(response)
5673 this.uploadComplete= true;
5674 if (this.haveProgress) {
5675 Roo.MessageBox.hide();
5679 var result = this.processResponse(response);
5680 if(result === true || result.success){
5681 this.form.afterAction(this, true);
5685 this.form.markInvalid(result.errors);
5686 this.failureType = Roo.form.Action.SERVER_INVALID;
5688 this.form.afterAction(this, false);
5690 failure : function(response)
5692 this.uploadComplete= true;
5693 if (this.haveProgress) {
5694 Roo.MessageBox.hide();
5697 this.response = response;
5698 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5699 this.form.afterAction(this, false);
5702 handleResponse : function(response){
5703 if(this.form.errorReader){
5704 var rs = this.form.errorReader.read(response);
5707 for(var i = 0, len = rs.records.length; i < len; i++) {
5708 var r = rs.records[i];
5712 if(errors.length < 1){
5716 success : rs.success,
5722 ret = Roo.decode(response.responseText);
5726 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
5736 Roo.form.Action.Load = function(form, options){
5737 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
5738 this.reader = this.form.reader;
5741 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
5746 Roo.Ajax.request(Roo.apply(
5747 this.createCallback(), {
5748 method:this.getMethod(),
5749 url:this.getUrl(false),
5750 params:this.getParams()
5754 success : function(response){
5756 var result = this.processResponse(response);
5757 if(result === true || !result.success || !result.data){
5758 this.failureType = Roo.form.Action.LOAD_FAILURE;
5759 this.form.afterAction(this, false);
5762 this.form.clearInvalid();
5763 this.form.setValues(result.data);
5764 this.form.afterAction(this, true);
5767 handleResponse : function(response){
5768 if(this.form.reader){
5769 var rs = this.form.reader.read(response);
5770 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
5772 success : rs.success,
5776 return Roo.decode(response.responseText);
5780 Roo.form.Action.ACTION_TYPES = {
5781 'load' : Roo.form.Action.Load,
5782 'submit' : Roo.form.Action.Submit
5791 * @class Roo.bootstrap.Form
5792 * @extends Roo.bootstrap.Component
5793 * Bootstrap Form class
5794 * @cfg {String} method GET | POST (default POST)
5795 * @cfg {String} labelAlign top | left (default top)
5796 * @cfg {String} align left | right - for navbars
5801 * @param {Object} config The config object
5805 Roo.bootstrap.Form = function(config){
5806 Roo.bootstrap.Form.superclass.constructor.call(this, config);
5809 * @event clientvalidation
5810 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
5811 * @param {Form} this
5812 * @param {Boolean} valid true if the form has passed client-side validation
5814 clientvalidation: true,
5816 * @event beforeaction
5817 * Fires before any action is performed. Return false to cancel the action.
5818 * @param {Form} this
5819 * @param {Action} action The action to be performed
5823 * @event actionfailed
5824 * Fires when an action fails.
5825 * @param {Form} this
5826 * @param {Action} action The action that failed
5828 actionfailed : true,
5830 * @event actioncomplete
5831 * Fires when an action is completed.
5832 * @param {Form} this
5833 * @param {Action} action The action that completed
5835 actioncomplete : true
5840 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
5843 * @cfg {String} method
5844 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
5849 * The URL to use for form actions if one isn't supplied in the action options.
5852 * @cfg {Boolean} fileUpload
5853 * Set to true if this form is a file upload.
5857 * @cfg {Object} baseParams
5858 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
5862 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
5866 * @cfg {Sting} align (left|right) for navbar forms
5871 activeAction : null,
5874 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5875 * element by passing it or its id or mask the form itself by passing in true.
5878 waitMsgTarget : false,
5883 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5884 * element by passing it or its id or mask the form itself by passing in true.
5888 getAutoCreate : function(){
5892 method : this.method || 'POST',
5893 id : this.id || Roo.id(),
5896 if (this.parent().xtype.match(/^Nav/)) {
5897 cfg.cls = 'navbar-form navbar-' + this.align;
5901 if (this.labelAlign == 'left' ) {
5902 cfg.cls += ' form-horizontal';
5908 initEvents : function()
5910 this.el.on('submit', this.onSubmit, this);
5911 // this was added as random key presses on the form where triggering form submit.
5912 this.el.on('keypress', function(e) {
5913 if (e.getCharCode() != 13) {
5916 // we might need to allow it for textareas.. and some other items.
5917 // check e.getTarget().
5919 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
5923 Roo.log("keypress blocked");
5931 onSubmit : function(e){
5936 * Returns true if client-side validation on the form is successful.
5939 isValid : function(){
5940 var items = this.getItems();
5942 items.each(function(f){
5951 * Returns true if any fields in this form have changed since their original load.
5954 isDirty : function(){
5956 var items = this.getItems();
5957 items.each(function(f){
5967 * Performs a predefined action (submit or load) or custom actions you define on this form.
5968 * @param {String} actionName The name of the action type
5969 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
5970 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
5971 * accept other config options):
5973 Property Type Description
5974 ---------------- --------------- ----------------------------------------------------------------------------------
5975 url String The url for the action (defaults to the form's url)
5976 method String The form method to use (defaults to the form's method, or POST if not defined)
5977 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
5978 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
5979 validate the form on the client (defaults to false)
5981 * @return {BasicForm} this
5983 doAction : function(action, options){
5984 if(typeof action == 'string'){
5985 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
5987 if(this.fireEvent('beforeaction', this, action) !== false){
5988 this.beforeAction(action);
5989 action.run.defer(100, action);
5995 beforeAction : function(action){
5996 var o = action.options;
5998 // not really supported yet.. ??
6000 //if(this.waitMsgTarget === true){
6001 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6002 //}else if(this.waitMsgTarget){
6003 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6004 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6006 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6012 afterAction : function(action, success){
6013 this.activeAction = null;
6014 var o = action.options;
6016 //if(this.waitMsgTarget === true){
6018 //}else if(this.waitMsgTarget){
6019 // this.waitMsgTarget.unmask();
6021 // Roo.MessageBox.updateProgress(1);
6022 // Roo.MessageBox.hide();
6029 Roo.callback(o.success, o.scope, [this, action]);
6030 this.fireEvent('actioncomplete', this, action);
6034 // failure condition..
6035 // we have a scenario where updates need confirming.
6036 // eg. if a locking scenario exists..
6037 // we look for { errors : { needs_confirm : true }} in the response.
6039 (typeof(action.result) != 'undefined') &&
6040 (typeof(action.result.errors) != 'undefined') &&
6041 (typeof(action.result.errors.needs_confirm) != 'undefined')
6044 Roo.log("not supported yet");
6047 Roo.MessageBox.confirm(
6048 "Change requires confirmation",
6049 action.result.errorMsg,
6054 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6064 Roo.callback(o.failure, o.scope, [this, action]);
6065 // show an error message if no failed handler is set..
6066 if (!this.hasListener('actionfailed')) {
6067 Roo.log("need to add dialog support");
6069 Roo.MessageBox.alert("Error",
6070 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6071 action.result.errorMsg :
6072 "Saving Failed, please check your entries or try again"
6077 this.fireEvent('actionfailed', this, action);
6082 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6083 * @param {String} id The value to search for
6086 findField : function(id){
6087 var items = this.getItems();
6088 var field = items.get(id);
6090 items.each(function(f){
6091 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6098 return field || null;
6101 * Mark fields in this form invalid in bulk.
6102 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6103 * @return {BasicForm} this
6105 markInvalid : function(errors){
6106 if(errors instanceof Array){
6107 for(var i = 0, len = errors.length; i < len; i++){
6108 var fieldError = errors[i];
6109 var f = this.findField(fieldError.id);
6111 f.markInvalid(fieldError.msg);
6117 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6118 field.markInvalid(errors[id]);
6122 //Roo.each(this.childForms || [], function (f) {
6123 // f.markInvalid(errors);
6130 * Set values for fields in this form in bulk.
6131 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6132 * @return {BasicForm} this
6134 setValues : function(values){
6135 if(values instanceof Array){ // array of objects
6136 for(var i = 0, len = values.length; i < len; i++){
6138 var f = this.findField(v.id);
6140 f.setValue(v.value);
6141 if(this.trackResetOnLoad){
6142 f.originalValue = f.getValue();
6146 }else{ // object hash
6149 if(typeof values[id] != 'function' && (field = this.findField(id))){
6151 if (field.setFromData &&
6153 field.displayField &&
6154 // combos' with local stores can
6155 // be queried via setValue()
6156 // to set their value..
6157 (field.store && !field.store.isLocal)
6161 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6162 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6163 field.setFromData(sd);
6166 field.setValue(values[id]);
6170 if(this.trackResetOnLoad){
6171 field.originalValue = field.getValue();
6177 //Roo.each(this.childForms || [], function (f) {
6178 // f.setValues(values);
6185 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6186 * they are returned as an array.
6187 * @param {Boolean} asString
6190 getValues : function(asString){
6191 //if (this.childForms) {
6192 // copy values from the child forms
6193 // Roo.each(this.childForms, function (f) {
6194 // this.setValues(f.getValues());
6200 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6201 if(asString === true){
6204 return Roo.urlDecode(fs);
6208 * Returns the fields in this form as an object with key/value pairs.
6209 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6212 getFieldValues : function(with_hidden)
6214 var items = this.getItems();
6216 items.each(function(f){
6220 var v = f.getValue();
6221 if (f.inputType =='radio') {
6222 if (typeof(ret[f.getName()]) == 'undefined') {
6223 ret[f.getName()] = ''; // empty..
6226 if (!f.el.dom.checked) {
6234 // not sure if this supported any more..
6235 if ((typeof(v) == 'object') && f.getRawValue) {
6236 v = f.getRawValue() ; // dates..
6238 // combo boxes where name != hiddenName...
6239 if (f.name != f.getName()) {
6240 ret[f.name] = f.getRawValue();
6242 ret[f.getName()] = v;
6249 * Clears all invalid messages in this form.
6250 * @return {BasicForm} this
6252 clearInvalid : function(){
6253 var items = this.getItems();
6255 items.each(function(f){
6266 * @return {BasicForm} this
6269 var items = this.getItems();
6270 items.each(function(f){
6274 Roo.each(this.childForms || [], function (f) {
6281 getItems : function()
6283 var r=new Roo.util.MixedCollection(false, function(o){
6284 return o.id || (o.id = Roo.id());
6286 var iter = function(el) {
6293 Roo.each(el.items,function(e) {
6312 * Ext JS Library 1.1.1
6313 * Copyright(c) 2006-2007, Ext JS, LLC.
6315 * Originally Released Under LGPL - original licence link has changed is not relivant.
6318 * <script type="text/javascript">
6321 * @class Roo.form.VTypes
6322 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6325 Roo.form.VTypes = function(){
6326 // closure these in so they are only created once.
6327 var alpha = /^[a-zA-Z_]+$/;
6328 var alphanum = /^[a-zA-Z0-9_]+$/;
6329 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6330 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6332 // All these messages and functions are configurable
6335 * The function used to validate email addresses
6336 * @param {String} value The email address
6338 'email' : function(v){
6339 return email.test(v);
6342 * The error text to display when the email validation function returns false
6345 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6347 * The keystroke filter mask to be applied on email input
6350 'emailMask' : /[a-z0-9_\.\-@]/i,
6353 * The function used to validate URLs
6354 * @param {String} value The URL
6356 'url' : function(v){
6360 * The error text to display when the url validation function returns false
6363 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6366 * The function used to validate alpha values
6367 * @param {String} value The value
6369 'alpha' : function(v){
6370 return alpha.test(v);
6373 * The error text to display when the alpha validation function returns false
6376 'alphaText' : 'This field should only contain letters and _',
6378 * The keystroke filter mask to be applied on alpha input
6381 'alphaMask' : /[a-z_]/i,
6384 * The function used to validate alphanumeric values
6385 * @param {String} value The value
6387 'alphanum' : function(v){
6388 return alphanum.test(v);
6391 * The error text to display when the alphanumeric validation function returns false
6394 'alphanumText' : 'This field should only contain letters, numbers and _',
6396 * The keystroke filter mask to be applied on alphanumeric input
6399 'alphanumMask' : /[a-z0-9_]/i
6409 * @class Roo.bootstrap.Input
6410 * @extends Roo.bootstrap.Component
6411 * Bootstrap Input class
6412 * @cfg {Boolean} disabled is it disabled
6413 * @cfg {String} fieldLabel - the label associated
6414 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6415 * @cfg {String} name name of the input
6416 * @cfg {string} fieldLabel - the label associated
6417 * @cfg {string} inputType - input / file submit ...
6418 * @cfg {string} placeholder - placeholder to put in text.
6419 * @cfg {string} before - input group add on before
6420 * @cfg {string} after - input group add on after
6421 * @cfg {string} size - (lg|sm) or leave empty..
6422 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6423 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6424 * @cfg {Number} md colspan out of 12 for computer-sized screens
6425 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6426 * @cfg {string} value default value of the input
6427 * @cfg {Number} labelWidth set the width of label (0-12)
6428 * @cfg {String} labelAlign (top|left)
6429 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6430 * @cfg {String} align (left|center|right) Default left
6431 * @cfg {Boolean} formatedValue (true | false) Default false
6435 * Create a new Input
6436 * @param {Object} config The config object
6439 Roo.bootstrap.Input = function(config){
6440 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6445 * Fires when this field receives input focus.
6446 * @param {Roo.form.Field} this
6451 * Fires when this field loses input focus.
6452 * @param {Roo.form.Field} this
6457 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6458 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6459 * @param {Roo.form.Field} this
6460 * @param {Roo.EventObject} e The event object
6465 * Fires just before the field blurs if the field value has changed.
6466 * @param {Roo.form.Field} this
6467 * @param {Mixed} newValue The new value
6468 * @param {Mixed} oldValue The original value
6473 * Fires after the field has been marked as invalid.
6474 * @param {Roo.form.Field} this
6475 * @param {String} msg The validation message
6480 * Fires after the field has been validated with no errors.
6481 * @param {Roo.form.Field} this
6486 * Fires after the key up
6487 * @param {Roo.form.Field} this
6488 * @param {Roo.EventObject} e The event Object
6494 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6496 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6497 automatic validation (defaults to "keyup").
6499 validationEvent : "keyup",
6501 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6503 validateOnBlur : true,
6505 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6507 validationDelay : 250,
6509 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6511 focusClass : "x-form-focus", // not needed???
6515 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6517 invalidClass : "has-error",
6520 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6522 selectOnFocus : false,
6525 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6529 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6534 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6536 disableKeyFilter : false,
6539 * @cfg {Boolean} disabled True to disable the field (defaults to false).
6543 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6547 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6549 blankText : "This field is required",
6552 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
6556 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
6558 maxLength : Number.MAX_VALUE,
6560 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
6562 minLengthText : "The minimum length for this field is {0}",
6564 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
6566 maxLengthText : "The maximum length for this field is {0}",
6570 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
6571 * If available, this function will be called only after the basic validators all return true, and will be passed the
6572 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
6576 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
6577 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
6578 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
6582 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
6605 formatedValue : false,
6607 parentLabelAlign : function()
6610 while (parent.parent()) {
6611 parent = parent.parent();
6612 if (typeof(parent.labelAlign) !='undefined') {
6613 return parent.labelAlign;
6620 getAutoCreate : function(){
6622 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6628 if(this.inputType != 'hidden'){
6629 cfg.cls = 'form-group' //input-group
6635 type : this.inputType,
6637 cls : 'form-control',
6638 placeholder : this.placeholder || ''
6643 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
6646 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6647 input.maxLength = this.maxLength;
6650 if (this.disabled) {
6651 input.disabled=true;
6654 if (this.readOnly) {
6655 input.readonly=true;
6659 input.name = this.name;
6662 input.cls += ' input-' + this.size;
6665 ['xs','sm','md','lg'].map(function(size){
6666 if (settings[size]) {
6667 cfg.cls += ' col-' + size + '-' + settings[size];
6671 var inputblock = input;
6673 if (this.before || this.after) {
6676 cls : 'input-group',
6679 if (this.before && typeof(this.before) == 'string') {
6681 inputblock.cn.push({
6683 cls : 'roo-input-before input-group-addon',
6687 if (this.before && typeof(this.before) == 'object') {
6688 this.before = Roo.factory(this.before);
6689 Roo.log(this.before);
6690 inputblock.cn.push({
6692 cls : 'roo-input-before input-group-' +
6693 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6697 inputblock.cn.push(input);
6699 if (this.after && typeof(this.after) == 'string') {
6700 inputblock.cn.push({
6702 cls : 'roo-input-after input-group-addon',
6706 if (this.after && typeof(this.after) == 'object') {
6707 this.after = Roo.factory(this.after);
6708 Roo.log(this.after);
6709 inputblock.cn.push({
6711 cls : 'roo-input-after input-group-' +
6712 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6717 if (align ==='left' && this.fieldLabel.length) {
6718 Roo.log("left and has label");
6724 cls : 'control-label col-sm-' + this.labelWidth,
6725 html : this.fieldLabel
6729 cls : "col-sm-" + (12 - this.labelWidth),
6736 } else if ( this.fieldLabel.length) {
6742 //cls : 'input-group-addon',
6743 html : this.fieldLabel
6753 Roo.log(" no label && no align");
6762 Roo.log('input-parentType: ' + this.parentType);
6764 if (this.parentType === 'Navbar' && this.parent().bar) {
6765 cfg.cls += ' navbar-form';
6773 * return the real input element.
6775 inputEl: function ()
6777 return this.el.select('input.form-control',true).first();
6779 setDisabled : function(v)
6781 var i = this.inputEl().dom;
6783 i.removeAttribute('disabled');
6787 i.setAttribute('disabled','true');
6789 initEvents : function()
6792 this.inputEl().on("keydown" , this.fireKey, this);
6793 this.inputEl().on("focus", this.onFocus, this);
6794 this.inputEl().on("blur", this.onBlur, this);
6796 this.inputEl().relayEvent('keyup', this);
6798 // reference to original value for reset
6799 this.originalValue = this.getValue();
6800 //Roo.form.TextField.superclass.initEvents.call(this);
6801 if(this.validationEvent == 'keyup'){
6802 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
6803 this.inputEl().on('keyup', this.filterValidation, this);
6805 else if(this.validationEvent !== false){
6806 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
6809 if(this.selectOnFocus){
6810 this.on("focus", this.preFocus, this);
6813 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
6814 this.inputEl().on("keypress", this.filterKeys, this);
6817 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
6818 this.el.on("click", this.autoSize, this);
6821 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
6822 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
6825 if (typeof(this.before) == 'object') {
6826 this.before.render(this.el.select('.roo-input-before',true).first());
6828 if (typeof(this.after) == 'object') {
6829 this.after.render(this.el.select('.roo-input-after',true).first());
6834 filterValidation : function(e){
6835 if(!e.isNavKeyPress()){
6836 this.validationTask.delay(this.validationDelay);
6840 * Validates the field value
6841 * @return {Boolean} True if the value is valid, else false
6843 validate : function(){
6844 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
6845 if(this.disabled || this.validateValue(this.getRawValue())){
6846 this.clearInvalid();
6854 * Validates a value according to the field's validation rules and marks the field as invalid
6855 * if the validation fails
6856 * @param {Mixed} value The value to validate
6857 * @return {Boolean} True if the value is valid, else false
6859 validateValue : function(value){
6860 if(value.length < 1) { // if it's blank
6861 if(this.allowBlank){
6862 this.clearInvalid();
6865 this.markInvalid(this.blankText);
6869 if(value.length < this.minLength){
6870 this.markInvalid(String.format(this.minLengthText, this.minLength));
6873 if(value.length > this.maxLength){
6874 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
6878 var vt = Roo.form.VTypes;
6879 if(!vt[this.vtype](value, this)){
6880 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
6884 if(typeof this.validator == "function"){
6885 var msg = this.validator(value);
6887 this.markInvalid(msg);
6891 if(this.regex && !this.regex.test(value)){
6892 this.markInvalid(this.regexText);
6901 fireKey : function(e){
6902 //Roo.log('field ' + e.getKey());
6903 if(e.isNavKeyPress()){
6904 this.fireEvent("specialkey", this, e);
6907 focus : function (selectText){
6909 this.inputEl().focus();
6910 if(selectText === true){
6911 this.inputEl().dom.select();
6917 onFocus : function(){
6918 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6919 // this.el.addClass(this.focusClass);
6922 this.hasFocus = true;
6923 this.startValue = this.getValue();
6924 this.fireEvent("focus", this);
6928 beforeBlur : Roo.emptyFn,
6932 onBlur : function(){
6934 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6935 //this.el.removeClass(this.focusClass);
6937 this.hasFocus = false;
6938 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
6941 var v = this.getValue();
6942 if(String(v) !== String(this.startValue)){
6943 this.fireEvent('change', this, v, this.startValue);
6945 this.fireEvent("blur", this);
6949 * Resets the current field value to the originally loaded value and clears any validation messages
6952 this.setValue(this.originalValue);
6953 this.clearInvalid();
6956 * Returns the name of the field
6957 * @return {Mixed} name The name field
6959 getName: function(){
6963 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
6964 * @return {Mixed} value The field value
6966 getValue : function(){
6968 if(this.formatedValue){
6972 return this.inputEl().getValue();
6975 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
6976 * @return {Mixed} value The field value
6978 getRawValue : function(){
6979 var v = this.inputEl().getValue();
6985 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
6986 * @param {Mixed} value The value to set
6988 setRawValue : function(v){
6989 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6992 selectText : function(start, end){
6993 var v = this.getRawValue();
6995 start = start === undefined ? 0 : start;
6996 end = end === undefined ? v.length : end;
6997 var d = this.inputEl().dom;
6998 if(d.setSelectionRange){
6999 d.setSelectionRange(start, end);
7000 }else if(d.createTextRange){
7001 var range = d.createTextRange();
7002 range.moveStart("character", start);
7003 range.moveEnd("character", v.length-end);
7010 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7011 * @param {Mixed} value The value to set
7013 setValue : function(v){
7016 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7022 processValue : function(value){
7023 if(this.stripCharsRe){
7024 var newValue = value.replace(this.stripCharsRe, '');
7025 if(newValue !== value){
7026 this.setRawValue(newValue);
7033 preFocus : function(){
7035 if(this.selectOnFocus){
7036 this.inputEl().dom.select();
7039 filterKeys : function(e){
7041 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7044 var c = e.getCharCode(), cc = String.fromCharCode(c);
7045 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7048 if(!this.maskRe.test(cc)){
7053 * Clear any invalid styles/messages for this field
7055 clearInvalid : function(){
7057 if(!this.el || this.preventMark){ // not rendered
7060 this.el.removeClass(this.invalidClass);
7062 switch(this.msgTarget){
7064 this.el.dom.qtip = '';
7067 this.el.dom.title = '';
7071 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7076 this.errorIcon.dom.qtip = '';
7077 this.errorIcon.hide();
7078 this.un('resize', this.alignErrorIcon, this);
7082 var t = Roo.getDom(this.msgTarget);
7084 t.style.display = 'none';
7088 this.fireEvent('valid', this);
7091 * Mark this field as invalid
7092 * @param {String} msg The validation message
7094 markInvalid : function(msg){
7095 if(!this.el || this.preventMark){ // not rendered
7098 this.el.addClass(this.invalidClass);
7100 msg = msg || this.invalidText;
7101 switch(this.msgTarget){
7103 this.el.dom.qtip = msg;
7104 this.el.dom.qclass = 'x-form-invalid-tip';
7105 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7106 Roo.QuickTips.enable();
7110 this.el.dom.title = msg;
7114 var elp = this.el.findParent('.x-form-element', 5, true);
7115 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7116 this.errorEl.setWidth(elp.getWidth(true)-20);
7118 this.errorEl.update(msg);
7119 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7122 if(!this.errorIcon){
7123 var elp = this.el.findParent('.x-form-element', 5, true);
7124 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7126 this.alignErrorIcon();
7127 this.errorIcon.dom.qtip = msg;
7128 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7129 this.errorIcon.show();
7130 this.on('resize', this.alignErrorIcon, this);
7133 var t = Roo.getDom(this.msgTarget);
7135 t.style.display = this.msgDisplay;
7139 this.fireEvent('invalid', this, msg);
7142 SafariOnKeyDown : function(event)
7144 // this is a workaround for a password hang bug on chrome/ webkit.
7146 var isSelectAll = false;
7148 if(this.inputEl().dom.selectionEnd > 0){
7149 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7151 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7152 event.preventDefault();
7157 if(isSelectAll){ // backspace and delete key
7159 event.preventDefault();
7160 // this is very hacky as keydown always get's upper case.
7162 var cc = String.fromCharCode(event.getCharCode());
7163 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7167 adjustWidth : function(tag, w){
7168 tag = tag.toLowerCase();
7169 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7170 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7174 if(tag == 'textarea'){
7177 }else if(Roo.isOpera){
7181 if(tag == 'textarea'){
7200 * @class Roo.bootstrap.TextArea
7201 * @extends Roo.bootstrap.Input
7202 * Bootstrap TextArea class
7203 * @cfg {Number} cols Specifies the visible width of a text area
7204 * @cfg {Number} rows Specifies the visible number of lines in a text area
7205 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7206 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7207 * @cfg {string} html text
7210 * Create a new TextArea
7211 * @param {Object} config The config object
7214 Roo.bootstrap.TextArea = function(config){
7215 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7219 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7229 getAutoCreate : function(){
7231 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7242 value : this.value || '',
7243 html: this.html || '',
7244 cls : 'form-control',
7245 placeholder : this.placeholder || ''
7249 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7250 input.maxLength = this.maxLength;
7254 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7258 input.cols = this.cols;
7261 if (this.readOnly) {
7262 input.readonly = true;
7266 input.name = this.name;
7270 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7274 ['xs','sm','md','lg'].map(function(size){
7275 if (settings[size]) {
7276 cfg.cls += ' col-' + size + '-' + settings[size];
7280 var inputblock = input;
7282 if (this.before || this.after) {
7285 cls : 'input-group',
7289 inputblock.cn.push({
7291 cls : 'input-group-addon',
7295 inputblock.cn.push(input);
7297 inputblock.cn.push({
7299 cls : 'input-group-addon',
7306 if (align ==='left' && this.fieldLabel.length) {
7307 Roo.log("left and has label");
7313 cls : 'control-label col-sm-' + this.labelWidth,
7314 html : this.fieldLabel
7318 cls : "col-sm-" + (12 - this.labelWidth),
7325 } else if ( this.fieldLabel.length) {
7331 //cls : 'input-group-addon',
7332 html : this.fieldLabel
7342 Roo.log(" no label && no align");
7352 if (this.disabled) {
7353 input.disabled=true;
7360 * return the real textarea element.
7362 inputEl: function ()
7364 return this.el.select('textarea.form-control',true).first();
7372 * trigger field - base class for combo..
7377 * @class Roo.bootstrap.TriggerField
7378 * @extends Roo.bootstrap.Input
7379 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7380 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7381 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7382 * for which you can provide a custom implementation. For example:
7384 var trigger = new Roo.bootstrap.TriggerField();
7385 trigger.onTriggerClick = myTriggerFn;
7386 trigger.applyTo('my-field');
7389 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7390 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7391 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7392 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7394 * Create a new TriggerField.
7395 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7396 * to the base TextField)
7398 Roo.bootstrap.TriggerField = function(config){
7399 this.mimicing = false;
7400 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7403 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7405 * @cfg {String} triggerClass A CSS class to apply to the trigger
7408 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7412 /** @cfg {Boolean} grow @hide */
7413 /** @cfg {Number} growMin @hide */
7414 /** @cfg {Number} growMax @hide */
7420 autoSize: Roo.emptyFn,
7427 actionMode : 'wrap',
7431 getAutoCreate : function(){
7433 var parent = this.parent();
7435 var align = this.labelAlign || this.parentLabelAlign();
7440 cls: 'form-group' //input-group
7447 type : this.inputType,
7448 cls : 'form-control',
7449 autocomplete: 'off',
7450 placeholder : this.placeholder || ''
7454 input.name = this.name;
7457 input.cls += ' input-' + this.size;
7460 if (this.disabled) {
7461 input.disabled=true;
7464 var inputblock = input;
7466 if (this.before || this.after) {
7469 cls : 'input-group',
7473 inputblock.cn.push({
7475 cls : 'input-group-addon',
7479 inputblock.cn.push(input);
7481 inputblock.cn.push({
7483 cls : 'input-group-addon',
7496 cls: 'form-hidden-field'
7504 Roo.log('multiple');
7512 cls: 'form-hidden-field'
7516 cls: 'select2-choices',
7520 cls: 'select2-search-field',
7533 cls: 'select2-container input-group',
7538 cls: 'typeahead typeahead-long dropdown-menu',
7539 style: 'display:none'
7547 cls : 'input-group-addon btn dropdown-toggle',
7555 cls: 'combobox-clear',
7569 combobox.cls += ' select2-container-multi';
7572 if (align ==='left' && this.fieldLabel.length) {
7574 Roo.log("left and has label");
7580 cls : 'control-label col-sm-' + this.labelWidth,
7581 html : this.fieldLabel
7585 cls : "col-sm-" + (12 - this.labelWidth),
7592 } else if ( this.fieldLabel.length) {
7598 //cls : 'input-group-addon',
7599 html : this.fieldLabel
7609 Roo.log(" no label && no align");
7616 ['xs','sm','md','lg'].map(function(size){
7617 if (settings[size]) {
7618 cfg.cls += ' col-' + size + '-' + settings[size];
7629 onResize : function(w, h){
7630 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
7631 // if(typeof w == 'number'){
7632 // var x = w - this.trigger.getWidth();
7633 // this.inputEl().setWidth(this.adjustWidth('input', x));
7634 // this.trigger.setStyle('left', x+'px');
7639 adjustSize : Roo.BoxComponent.prototype.adjustSize,
7642 getResizeEl : function(){
7643 return this.inputEl();
7647 getPositionEl : function(){
7648 return this.inputEl();
7652 alignErrorIcon : function(){
7653 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
7657 initEvents : function(){
7659 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
7660 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
7662 this.trigger = this.el.select('span.dropdown-toggle',true).first();
7663 if(this.hideTrigger){
7664 this.trigger.setDisplayed(false);
7666 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
7670 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
7673 //this.trigger.addClassOnOver('x-form-trigger-over');
7674 //this.trigger.addClassOnClick('x-form-trigger-click');
7677 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
7682 initTrigger : function(){
7687 onDestroy : function(){
7689 this.trigger.removeAllListeners();
7690 // this.trigger.remove();
7693 // this.wrap.remove();
7695 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
7699 onFocus : function(){
7700 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
7703 this.wrap.addClass('x-trigger-wrap-focus');
7704 this.mimicing = true;
7705 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
7706 if(this.monitorTab){
7707 this.el.on("keydown", this.checkTab, this);
7714 checkTab : function(e){
7715 if(e.getKey() == e.TAB){
7721 onBlur : function(){
7726 mimicBlur : function(e, t){
7728 if(!this.wrap.contains(t) && this.validateBlur()){
7735 triggerBlur : function(){
7736 this.mimicing = false;
7737 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
7738 if(this.monitorTab){
7739 this.el.un("keydown", this.checkTab, this);
7741 //this.wrap.removeClass('x-trigger-wrap-focus');
7742 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
7746 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
7747 validateBlur : function(e, t){
7752 onDisable : function(){
7753 this.inputEl().dom.disabled = true;
7754 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
7756 // this.wrap.addClass('x-item-disabled');
7761 onEnable : function(){
7762 this.inputEl().dom.disabled = false;
7763 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
7765 // this.el.removeClass('x-item-disabled');
7770 onShow : function(){
7771 var ae = this.getActionEl();
7774 ae.dom.style.display = '';
7775 ae.dom.style.visibility = 'visible';
7781 onHide : function(){
7782 var ae = this.getActionEl();
7783 ae.dom.style.display = 'none';
7787 * The function that should handle the trigger's click event. This method does nothing by default until overridden
7788 * by an implementing function.
7790 * @param {EventObject} e
7792 onTriggerClick : Roo.emptyFn
7796 * Ext JS Library 1.1.1
7797 * Copyright(c) 2006-2007, Ext JS, LLC.
7799 * Originally Released Under LGPL - original licence link has changed is not relivant.
7802 * <script type="text/javascript">
7807 * @class Roo.data.SortTypes
7809 * Defines the default sorting (casting?) comparison functions used when sorting data.
7811 Roo.data.SortTypes = {
7813 * Default sort that does nothing
7814 * @param {Mixed} s The value being converted
7815 * @return {Mixed} The comparison value
7822 * The regular expression used to strip tags
7826 stripTagsRE : /<\/?[^>]+>/gi,
7829 * Strips all HTML tags to sort on text only
7830 * @param {Mixed} s The value being converted
7831 * @return {String} The comparison value
7833 asText : function(s){
7834 return String(s).replace(this.stripTagsRE, "");
7838 * Strips all HTML tags to sort on text only - Case insensitive
7839 * @param {Mixed} s The value being converted
7840 * @return {String} The comparison value
7842 asUCText : function(s){
7843 return String(s).toUpperCase().replace(this.stripTagsRE, "");
7847 * Case insensitive string
7848 * @param {Mixed} s The value being converted
7849 * @return {String} The comparison value
7851 asUCString : function(s) {
7852 return String(s).toUpperCase();
7857 * @param {Mixed} s The value being converted
7858 * @return {Number} The comparison value
7860 asDate : function(s) {
7864 if(s instanceof Date){
7867 return Date.parse(String(s));
7872 * @param {Mixed} s The value being converted
7873 * @return {Float} The comparison value
7875 asFloat : function(s) {
7876 var val = parseFloat(String(s).replace(/,/g, ""));
7877 if(isNaN(val)) val = 0;
7883 * @param {Mixed} s The value being converted
7884 * @return {Number} The comparison value
7886 asInt : function(s) {
7887 var val = parseInt(String(s).replace(/,/g, ""));
7888 if(isNaN(val)) val = 0;
7893 * Ext JS Library 1.1.1
7894 * Copyright(c) 2006-2007, Ext JS, LLC.
7896 * Originally Released Under LGPL - original licence link has changed is not relivant.
7899 * <script type="text/javascript">
7903 * @class Roo.data.Record
7904 * Instances of this class encapsulate both record <em>definition</em> information, and record
7905 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
7906 * to access Records cached in an {@link Roo.data.Store} object.<br>
7908 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
7909 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
7912 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
7914 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
7915 * {@link #create}. The parameters are the same.
7916 * @param {Array} data An associative Array of data values keyed by the field name.
7917 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
7918 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
7919 * not specified an integer id is generated.
7921 Roo.data.Record = function(data, id){
7922 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
7927 * Generate a constructor for a specific record layout.
7928 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
7929 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
7930 * Each field definition object may contain the following properties: <ul>
7931 * <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,
7932 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
7933 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
7934 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
7935 * is being used, then this is a string containing the javascript expression to reference the data relative to
7936 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
7937 * to the data item relative to the record element. If the mapping expression is the same as the field name,
7938 * this may be omitted.</p></li>
7939 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
7940 * <ul><li>auto (Default, implies no conversion)</li>
7945 * <li>date</li></ul></p></li>
7946 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
7947 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
7948 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
7949 * by the Reader into an object that will be stored in the Record. It is passed the
7950 * following parameters:<ul>
7951 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
7953 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
7955 * <br>usage:<br><pre><code>
7956 var TopicRecord = Roo.data.Record.create(
7957 {name: 'title', mapping: 'topic_title'},
7958 {name: 'author', mapping: 'username'},
7959 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
7960 {name: 'lastPost', mapping: 'post_time', type: 'date'},
7961 {name: 'lastPoster', mapping: 'user2'},
7962 {name: 'excerpt', mapping: 'post_text'}
7965 var myNewRecord = new TopicRecord({
7966 title: 'Do my job please',
7969 lastPost: new Date(),
7970 lastPoster: 'Animal',
7971 excerpt: 'No way dude!'
7973 myStore.add(myNewRecord);
7978 Roo.data.Record.create = function(o){
7980 f.superclass.constructor.apply(this, arguments);
7982 Roo.extend(f, Roo.data.Record);
7983 var p = f.prototype;
7984 p.fields = new Roo.util.MixedCollection(false, function(field){
7987 for(var i = 0, len = o.length; i < len; i++){
7988 p.fields.add(new Roo.data.Field(o[i]));
7990 f.getField = function(name){
7991 return p.fields.get(name);
7996 Roo.data.Record.AUTO_ID = 1000;
7997 Roo.data.Record.EDIT = 'edit';
7998 Roo.data.Record.REJECT = 'reject';
7999 Roo.data.Record.COMMIT = 'commit';
8001 Roo.data.Record.prototype = {
8003 * Readonly flag - true if this record has been modified.
8012 join : function(store){
8017 * Set the named field to the specified value.
8018 * @param {String} name The name of the field to set.
8019 * @param {Object} value The value to set the field to.
8021 set : function(name, value){
8022 if(this.data[name] == value){
8029 if(typeof this.modified[name] == 'undefined'){
8030 this.modified[name] = this.data[name];
8032 this.data[name] = value;
8033 if(!this.editing && this.store){
8034 this.store.afterEdit(this);
8039 * Get the value of the named field.
8040 * @param {String} name The name of the field to get the value of.
8041 * @return {Object} The value of the field.
8043 get : function(name){
8044 return this.data[name];
8048 beginEdit : function(){
8049 this.editing = true;
8054 cancelEdit : function(){
8055 this.editing = false;
8056 delete this.modified;
8060 endEdit : function(){
8061 this.editing = false;
8062 if(this.dirty && this.store){
8063 this.store.afterEdit(this);
8068 * Usually called by the {@link Roo.data.Store} which owns the Record.
8069 * Rejects all changes made to the Record since either creation, or the last commit operation.
8070 * Modified fields are reverted to their original values.
8072 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8073 * of reject operations.
8075 reject : function(){
8076 var m = this.modified;
8078 if(typeof m[n] != "function"){
8079 this.data[n] = m[n];
8083 delete this.modified;
8084 this.editing = false;
8086 this.store.afterReject(this);
8091 * Usually called by the {@link Roo.data.Store} which owns the Record.
8092 * Commits all changes made to the Record since either creation, or the last commit operation.
8094 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8095 * of commit operations.
8097 commit : function(){
8099 delete this.modified;
8100 this.editing = false;
8102 this.store.afterCommit(this);
8107 hasError : function(){
8108 return this.error != null;
8112 clearError : function(){
8117 * Creates a copy of this record.
8118 * @param {String} id (optional) A new record id if you don't want to use this record's id
8121 copy : function(newId) {
8122 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8126 * Ext JS Library 1.1.1
8127 * Copyright(c) 2006-2007, Ext JS, LLC.
8129 * Originally Released Under LGPL - original licence link has changed is not relivant.
8132 * <script type="text/javascript">
8138 * @class Roo.data.Store
8139 * @extends Roo.util.Observable
8140 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8141 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8143 * 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
8144 * has no knowledge of the format of the data returned by the Proxy.<br>
8146 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8147 * instances from the data object. These records are cached and made available through accessor functions.
8149 * Creates a new Store.
8150 * @param {Object} config A config object containing the objects needed for the Store to access data,
8151 * and read the data into Records.
8153 Roo.data.Store = function(config){
8154 this.data = new Roo.util.MixedCollection(false);
8155 this.data.getKey = function(o){
8158 this.baseParams = {};
8165 "multisort" : "_multisort"
8168 if(config && config.data){
8169 this.inlineData = config.data;
8173 Roo.apply(this, config);
8175 if(this.reader){ // reader passed
8176 this.reader = Roo.factory(this.reader, Roo.data);
8177 this.reader.xmodule = this.xmodule || false;
8178 if(!this.recordType){
8179 this.recordType = this.reader.recordType;
8181 if(this.reader.onMetaChange){
8182 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8186 if(this.recordType){
8187 this.fields = this.recordType.prototype.fields;
8193 * @event datachanged
8194 * Fires when the data cache has changed, and a widget which is using this Store
8195 * as a Record cache should refresh its view.
8196 * @param {Store} this
8201 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8202 * @param {Store} this
8203 * @param {Object} meta The JSON metadata
8208 * Fires when Records have been added to the Store
8209 * @param {Store} this
8210 * @param {Roo.data.Record[]} records The array of Records added
8211 * @param {Number} index The index at which the record(s) were added
8216 * Fires when a Record has been removed from the Store
8217 * @param {Store} this
8218 * @param {Roo.data.Record} record The Record that was removed
8219 * @param {Number} index The index at which the record was removed
8224 * Fires when a Record has been updated
8225 * @param {Store} this
8226 * @param {Roo.data.Record} record The Record that was updated
8227 * @param {String} operation The update operation being performed. Value may be one of:
8229 Roo.data.Record.EDIT
8230 Roo.data.Record.REJECT
8231 Roo.data.Record.COMMIT
8237 * Fires when the data cache has been cleared.
8238 * @param {Store} this
8243 * Fires before a request is made for a new data object. If the beforeload handler returns false
8244 * the load action will be canceled.
8245 * @param {Store} this
8246 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8250 * @event beforeloadadd
8251 * Fires after a new set of Records has been loaded.
8252 * @param {Store} this
8253 * @param {Roo.data.Record[]} records The Records that were loaded
8254 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8256 beforeloadadd : true,
8259 * Fires after a new set of Records has been loaded, before they are added to the store.
8260 * @param {Store} this
8261 * @param {Roo.data.Record[]} records The Records that were loaded
8262 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8263 * @params {Object} return from reader
8267 * @event loadexception
8268 * Fires if an exception occurs in the Proxy during loading.
8269 * Called with the signature of the Proxy's "loadexception" event.
8270 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8273 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8274 * @param {Object} load options
8275 * @param {Object} jsonData from your request (normally this contains the Exception)
8277 loadexception : true
8281 this.proxy = Roo.factory(this.proxy, Roo.data);
8282 this.proxy.xmodule = this.xmodule || false;
8283 this.relayEvents(this.proxy, ["loadexception"]);
8285 this.sortToggle = {};
8286 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8288 Roo.data.Store.superclass.constructor.call(this);
8290 if(this.inlineData){
8291 this.loadData(this.inlineData);
8292 delete this.inlineData;
8296 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8298 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8299 * without a remote query - used by combo/forms at present.
8303 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8306 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8309 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8310 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8313 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8314 * on any HTTP request
8317 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8320 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8324 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8325 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8330 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8331 * loaded or when a record is removed. (defaults to false).
8333 pruneModifiedRecords : false,
8339 * Add Records to the Store and fires the add event.
8340 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8342 add : function(records){
8343 records = [].concat(records);
8344 for(var i = 0, len = records.length; i < len; i++){
8345 records[i].join(this);
8347 var index = this.data.length;
8348 this.data.addAll(records);
8349 this.fireEvent("add", this, records, index);
8353 * Remove a Record from the Store and fires the remove event.
8354 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8356 remove : function(record){
8357 var index = this.data.indexOf(record);
8358 this.data.removeAt(index);
8359 if(this.pruneModifiedRecords){
8360 this.modified.remove(record);
8362 this.fireEvent("remove", this, record, index);
8366 * Remove all Records from the Store and fires the clear event.
8368 removeAll : function(){
8370 if(this.pruneModifiedRecords){
8373 this.fireEvent("clear", this);
8377 * Inserts Records to the Store at the given index and fires the add event.
8378 * @param {Number} index The start index at which to insert the passed Records.
8379 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8381 insert : function(index, records){
8382 records = [].concat(records);
8383 for(var i = 0, len = records.length; i < len; i++){
8384 this.data.insert(index, records[i]);
8385 records[i].join(this);
8387 this.fireEvent("add", this, records, index);
8391 * Get the index within the cache of the passed Record.
8392 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8393 * @return {Number} The index of the passed Record. Returns -1 if not found.
8395 indexOf : function(record){
8396 return this.data.indexOf(record);
8400 * Get the index within the cache of the Record with the passed id.
8401 * @param {String} id The id of the Record to find.
8402 * @return {Number} The index of the Record. Returns -1 if not found.
8404 indexOfId : function(id){
8405 return this.data.indexOfKey(id);
8409 * Get the Record with the specified id.
8410 * @param {String} id The id of the Record to find.
8411 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8413 getById : function(id){
8414 return this.data.key(id);
8418 * Get the Record at the specified index.
8419 * @param {Number} index The index of the Record to find.
8420 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8422 getAt : function(index){
8423 return this.data.itemAt(index);
8427 * Returns a range of Records between specified indices.
8428 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8429 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8430 * @return {Roo.data.Record[]} An array of Records
8432 getRange : function(start, end){
8433 return this.data.getRange(start, end);
8437 storeOptions : function(o){
8438 o = Roo.apply({}, o);
8441 this.lastOptions = o;
8445 * Loads the Record cache from the configured Proxy using the configured Reader.
8447 * If using remote paging, then the first load call must specify the <em>start</em>
8448 * and <em>limit</em> properties in the options.params property to establish the initial
8449 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8451 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8452 * and this call will return before the new data has been loaded. Perform any post-processing
8453 * in a callback function, or in a "load" event handler.</strong>
8455 * @param {Object} options An object containing properties which control loading options:<ul>
8456 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8457 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8458 * passed the following arguments:<ul>
8459 * <li>r : Roo.data.Record[]</li>
8460 * <li>options: Options object from the load call</li>
8461 * <li>success: Boolean success indicator</li></ul></li>
8462 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8463 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8466 load : function(options){
8467 options = options || {};
8468 if(this.fireEvent("beforeload", this, options) !== false){
8469 this.storeOptions(options);
8470 var p = Roo.apply(options.params || {}, this.baseParams);
8471 // if meta was not loaded from remote source.. try requesting it.
8472 if (!this.reader.metaFromRemote) {
8475 if(this.sortInfo && this.remoteSort){
8476 var pn = this.paramNames;
8477 p[pn["sort"]] = this.sortInfo.field;
8478 p[pn["dir"]] = this.sortInfo.direction;
8480 if (this.multiSort) {
8481 var pn = this.paramNames;
8482 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8485 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8490 * Reloads the Record cache from the configured Proxy using the configured Reader and
8491 * the options from the last load operation performed.
8492 * @param {Object} options (optional) An object containing properties which may override the options
8493 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8494 * the most recently used options are reused).
8496 reload : function(options){
8497 this.load(Roo.applyIf(options||{}, this.lastOptions));
8501 // Called as a callback by the Reader during a load operation.
8502 loadRecords : function(o, options, success){
8503 if(!o || success === false){
8504 if(success !== false){
8505 this.fireEvent("load", this, [], options, o);
8507 if(options.callback){
8508 options.callback.call(options.scope || this, [], options, false);
8512 // if data returned failure - throw an exception.
8513 if (o.success === false) {
8514 // show a message if no listener is registered.
8515 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8516 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8518 // loadmask wil be hooked into this..
8519 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8522 var r = o.records, t = o.totalRecords || r.length;
8524 this.fireEvent("beforeloadadd", this, r, options, o);
8526 if(!options || options.add !== true){
8527 if(this.pruneModifiedRecords){
8530 for(var i = 0, len = r.length; i < len; i++){
8534 this.data = this.snapshot;
8535 delete this.snapshot;
8538 this.data.addAll(r);
8539 this.totalLength = t;
8541 this.fireEvent("datachanged", this);
8543 this.totalLength = Math.max(t, this.data.length+r.length);
8546 this.fireEvent("load", this, r, options, o);
8547 if(options.callback){
8548 options.callback.call(options.scope || this, r, options, true);
8554 * Loads data from a passed data block. A Reader which understands the format of the data
8555 * must have been configured in the constructor.
8556 * @param {Object} data The data block from which to read the Records. The format of the data expected
8557 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8558 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8560 loadData : function(o, append){
8561 var r = this.reader.readRecords(o);
8562 this.loadRecords(r, {add: append}, true);
8566 * Gets the number of cached records.
8568 * <em>If using paging, this may not be the total size of the dataset. If the data object
8569 * used by the Reader contains the dataset size, then the getTotalCount() function returns
8570 * the data set size</em>
8572 getCount : function(){
8573 return this.data.length || 0;
8577 * Gets the total number of records in the dataset as returned by the server.
8579 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8580 * the dataset size</em>
8582 getTotalCount : function(){
8583 return this.totalLength || 0;
8587 * Returns the sort state of the Store as an object with two properties:
8589 field {String} The name of the field by which the Records are sorted
8590 direction {String} The sort order, "ASC" or "DESC"
8593 getSortState : function(){
8594 return this.sortInfo;
8598 applySort : function(){
8599 if(this.sortInfo && !this.remoteSort){
8600 var s = this.sortInfo, f = s.field;
8601 var st = this.fields.get(f).sortType;
8602 var fn = function(r1, r2){
8603 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8604 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8606 this.data.sort(s.direction, fn);
8607 if(this.snapshot && this.snapshot != this.data){
8608 this.snapshot.sort(s.direction, fn);
8614 * Sets the default sort column and order to be used by the next load operation.
8615 * @param {String} fieldName The name of the field to sort by.
8616 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8618 setDefaultSort : function(field, dir){
8619 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
8624 * If remote sorting is used, the sort is performed on the server, and the cache is
8625 * reloaded. If local sorting is used, the cache is sorted internally.
8626 * @param {String} fieldName The name of the field to sort by.
8627 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8629 sort : function(fieldName, dir){
8630 var f = this.fields.get(fieldName);
8632 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
8634 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
8635 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
8640 this.sortToggle[f.name] = dir;
8641 this.sortInfo = {field: f.name, direction: dir};
8642 if(!this.remoteSort){
8644 this.fireEvent("datachanged", this);
8646 this.load(this.lastOptions);
8651 * Calls the specified function for each of the Records in the cache.
8652 * @param {Function} fn The function to call. The Record is passed as the first parameter.
8653 * Returning <em>false</em> aborts and exits the iteration.
8654 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
8656 each : function(fn, scope){
8657 this.data.each(fn, scope);
8661 * Gets all records modified since the last commit. Modified records are persisted across load operations
8662 * (e.g., during paging).
8663 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
8665 getModifiedRecords : function(){
8666 return this.modified;
8670 createFilterFn : function(property, value, anyMatch){
8671 if(!value.exec){ // not a regex
8672 value = String(value);
8673 if(value.length == 0){
8676 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
8679 return value.test(r.data[property]);
8684 * Sums the value of <i>property</i> for each record between start and end and returns the result.
8685 * @param {String} property A field on your records
8686 * @param {Number} start The record index to start at (defaults to 0)
8687 * @param {Number} end The last record index to include (defaults to length - 1)
8688 * @return {Number} The sum
8690 sum : function(property, start, end){
8691 var rs = this.data.items, v = 0;
8693 end = (end || end === 0) ? end : rs.length-1;
8695 for(var i = start; i <= end; i++){
8696 v += (rs[i].data[property] || 0);
8702 * Filter the records by a specified property.
8703 * @param {String} field A field on your records
8704 * @param {String/RegExp} value Either a string that the field
8705 * should start with or a RegExp to test against the field
8706 * @param {Boolean} anyMatch True to match any part not just the beginning
8708 filter : function(property, value, anyMatch){
8709 var fn = this.createFilterFn(property, value, anyMatch);
8710 return fn ? this.filterBy(fn) : this.clearFilter();
8714 * Filter by a function. The specified function will be called with each
8715 * record in this data source. If the function returns true the record is included,
8716 * otherwise it is filtered.
8717 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8718 * @param {Object} scope (optional) The scope of the function (defaults to this)
8720 filterBy : function(fn, scope){
8721 this.snapshot = this.snapshot || this.data;
8722 this.data = this.queryBy(fn, scope||this);
8723 this.fireEvent("datachanged", this);
8727 * Query the records by a specified property.
8728 * @param {String} field A field on your records
8729 * @param {String/RegExp} value Either a string that the field
8730 * should start with or a RegExp to test against the field
8731 * @param {Boolean} anyMatch True to match any part not just the beginning
8732 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8734 query : function(property, value, anyMatch){
8735 var fn = this.createFilterFn(property, value, anyMatch);
8736 return fn ? this.queryBy(fn) : this.data.clone();
8740 * Query by a function. The specified function will be called with each
8741 * record in this data source. If the function returns true the record is included
8743 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8744 * @param {Object} scope (optional) The scope of the function (defaults to this)
8745 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8747 queryBy : function(fn, scope){
8748 var data = this.snapshot || this.data;
8749 return data.filterBy(fn, scope||this);
8753 * Collects unique values for a particular dataIndex from this store.
8754 * @param {String} dataIndex The property to collect
8755 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
8756 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
8757 * @return {Array} An array of the unique values
8759 collect : function(dataIndex, allowNull, bypassFilter){
8760 var d = (bypassFilter === true && this.snapshot) ?
8761 this.snapshot.items : this.data.items;
8762 var v, sv, r = [], l = {};
8763 for(var i = 0, len = d.length; i < len; i++){
8764 v = d[i].data[dataIndex];
8766 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
8775 * Revert to a view of the Record cache with no filtering applied.
8776 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
8778 clearFilter : function(suppressEvent){
8779 if(this.snapshot && this.snapshot != this.data){
8780 this.data = this.snapshot;
8781 delete this.snapshot;
8782 if(suppressEvent !== true){
8783 this.fireEvent("datachanged", this);
8789 afterEdit : function(record){
8790 if(this.modified.indexOf(record) == -1){
8791 this.modified.push(record);
8793 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
8797 afterReject : function(record){
8798 this.modified.remove(record);
8799 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
8803 afterCommit : function(record){
8804 this.modified.remove(record);
8805 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
8809 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
8810 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
8812 commitChanges : function(){
8813 var m = this.modified.slice(0);
8815 for(var i = 0, len = m.length; i < len; i++){
8821 * Cancel outstanding changes on all changed records.
8823 rejectChanges : function(){
8824 var m = this.modified.slice(0);
8826 for(var i = 0, len = m.length; i < len; i++){
8831 onMetaChange : function(meta, rtype, o){
8832 this.recordType = rtype;
8833 this.fields = rtype.prototype.fields;
8834 delete this.snapshot;
8835 this.sortInfo = meta.sortInfo || this.sortInfo;
8837 this.fireEvent('metachange', this, this.reader.meta);
8840 moveIndex : function(data, type)
8842 var index = this.indexOf(data);
8844 var newIndex = index + type;
8848 this.insert(newIndex, data);
8853 * Ext JS Library 1.1.1
8854 * Copyright(c) 2006-2007, Ext JS, LLC.
8856 * Originally Released Under LGPL - original licence link has changed is not relivant.
8859 * <script type="text/javascript">
8863 * @class Roo.data.SimpleStore
8864 * @extends Roo.data.Store
8865 * Small helper class to make creating Stores from Array data easier.
8866 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
8867 * @cfg {Array} fields An array of field definition objects, or field name strings.
8868 * @cfg {Array} data The multi-dimensional array of data
8870 * @param {Object} config
8872 Roo.data.SimpleStore = function(config){
8873 Roo.data.SimpleStore.superclass.constructor.call(this, {
8875 reader: new Roo.data.ArrayReader({
8878 Roo.data.Record.create(config.fields)
8880 proxy : new Roo.data.MemoryProxy(config.data)
8884 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
8886 * Ext JS Library 1.1.1
8887 * Copyright(c) 2006-2007, Ext JS, LLC.
8889 * Originally Released Under LGPL - original licence link has changed is not relivant.
8892 * <script type="text/javascript">
8897 * @extends Roo.data.Store
8898 * @class Roo.data.JsonStore
8899 * Small helper class to make creating Stores for JSON data easier. <br/>
8901 var store = new Roo.data.JsonStore({
8902 url: 'get-images.php',
8904 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
8907 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
8908 * JsonReader and HttpProxy (unless inline data is provided).</b>
8909 * @cfg {Array} fields An array of field definition objects, or field name strings.
8911 * @param {Object} config
8913 Roo.data.JsonStore = function(c){
8914 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
8915 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
8916 reader: new Roo.data.JsonReader(c, c.fields)
8919 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
8921 * Ext JS Library 1.1.1
8922 * Copyright(c) 2006-2007, Ext JS, LLC.
8924 * Originally Released Under LGPL - original licence link has changed is not relivant.
8927 * <script type="text/javascript">
8931 Roo.data.Field = function(config){
8932 if(typeof config == "string"){
8933 config = {name: config};
8935 Roo.apply(this, config);
8941 var st = Roo.data.SortTypes;
8942 // named sortTypes are supported, here we look them up
8943 if(typeof this.sortType == "string"){
8944 this.sortType = st[this.sortType];
8947 // set default sortType for strings and dates
8951 this.sortType = st.asUCString;
8954 this.sortType = st.asDate;
8957 this.sortType = st.none;
8962 var stripRe = /[\$,%]/g;
8964 // prebuilt conversion function for this field, instead of
8965 // switching every time we're reading a value
8967 var cv, dateFormat = this.dateFormat;
8972 cv = function(v){ return v; };
8975 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
8979 return v !== undefined && v !== null && v !== '' ?
8980 parseInt(String(v).replace(stripRe, ""), 10) : '';
8985 return v !== undefined && v !== null && v !== '' ?
8986 parseFloat(String(v).replace(stripRe, ""), 10) : '';
8991 cv = function(v){ return v === true || v === "true" || v == 1; };
8998 if(v instanceof Date){
9002 if(dateFormat == "timestamp"){
9003 return new Date(v*1000);
9005 return Date.parseDate(v, dateFormat);
9007 var parsed = Date.parse(v);
9008 return parsed ? new Date(parsed) : null;
9017 Roo.data.Field.prototype = {
9025 * Ext JS Library 1.1.1
9026 * Copyright(c) 2006-2007, Ext JS, LLC.
9028 * Originally Released Under LGPL - original licence link has changed is not relivant.
9031 * <script type="text/javascript">
9034 // Base class for reading structured data from a data source. This class is intended to be
9035 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9038 * @class Roo.data.DataReader
9039 * Base class for reading structured data from a data source. This class is intended to be
9040 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9043 Roo.data.DataReader = function(meta, recordType){
9047 this.recordType = recordType instanceof Array ?
9048 Roo.data.Record.create(recordType) : recordType;
9051 Roo.data.DataReader.prototype = {
9053 * Create an empty record
9054 * @param {Object} data (optional) - overlay some values
9055 * @return {Roo.data.Record} record created.
9057 newRow : function(d) {
9059 this.recordType.prototype.fields.each(function(c) {
9061 case 'int' : da[c.name] = 0; break;
9062 case 'date' : da[c.name] = new Date(); break;
9063 case 'float' : da[c.name] = 0.0; break;
9064 case 'boolean' : da[c.name] = false; break;
9065 default : da[c.name] = ""; break;
9069 return new this.recordType(Roo.apply(da, d));
9074 * Ext JS Library 1.1.1
9075 * Copyright(c) 2006-2007, Ext JS, LLC.
9077 * Originally Released Under LGPL - original licence link has changed is not relivant.
9080 * <script type="text/javascript">
9084 * @class Roo.data.DataProxy
9085 * @extends Roo.data.Observable
9086 * This class is an abstract base class for implementations which provide retrieval of
9087 * unformatted data objects.<br>
9089 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9090 * (of the appropriate type which knows how to parse the data object) to provide a block of
9091 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9093 * Custom implementations must implement the load method as described in
9094 * {@link Roo.data.HttpProxy#load}.
9096 Roo.data.DataProxy = function(){
9100 * Fires before a network request is made to retrieve a data object.
9101 * @param {Object} This DataProxy object.
9102 * @param {Object} params The params parameter to the load function.
9107 * Fires before the load method's callback is called.
9108 * @param {Object} This DataProxy object.
9109 * @param {Object} o The data object.
9110 * @param {Object} arg The callback argument object passed to the load function.
9114 * @event loadexception
9115 * Fires if an Exception occurs during data retrieval.
9116 * @param {Object} This DataProxy object.
9117 * @param {Object} o The data object.
9118 * @param {Object} arg The callback argument object passed to the load function.
9119 * @param {Object} e The Exception.
9121 loadexception : true
9123 Roo.data.DataProxy.superclass.constructor.call(this);
9126 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9129 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9133 * Ext JS Library 1.1.1
9134 * Copyright(c) 2006-2007, Ext JS, LLC.
9136 * Originally Released Under LGPL - original licence link has changed is not relivant.
9139 * <script type="text/javascript">
9142 * @class Roo.data.MemoryProxy
9143 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9144 * to the Reader when its load method is called.
9146 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9148 Roo.data.MemoryProxy = function(data){
9152 Roo.data.MemoryProxy.superclass.constructor.call(this);
9156 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9158 * Load data from the requested source (in this case an in-memory
9159 * data object passed to the constructor), read the data object into
9160 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9161 * process that block using the passed callback.
9162 * @param {Object} params This parameter is not used by the MemoryProxy class.
9163 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9164 * object into a block of Roo.data.Records.
9165 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9166 * The function must be passed <ul>
9167 * <li>The Record block object</li>
9168 * <li>The "arg" argument from the load function</li>
9169 * <li>A boolean success indicator</li>
9171 * @param {Object} scope The scope in which to call the callback
9172 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9174 load : function(params, reader, callback, scope, arg){
9175 params = params || {};
9178 result = reader.readRecords(this.data);
9180 this.fireEvent("loadexception", this, arg, null, e);
9181 callback.call(scope, null, arg, false);
9184 callback.call(scope, result, arg, true);
9188 update : function(params, records){
9193 * Ext JS Library 1.1.1
9194 * Copyright(c) 2006-2007, Ext JS, LLC.
9196 * Originally Released Under LGPL - original licence link has changed is not relivant.
9199 * <script type="text/javascript">
9202 * @class Roo.data.HttpProxy
9203 * @extends Roo.data.DataProxy
9204 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9205 * configured to reference a certain URL.<br><br>
9207 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9208 * from which the running page was served.<br><br>
9210 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9212 * Be aware that to enable the browser to parse an XML document, the server must set
9213 * the Content-Type header in the HTTP response to "text/xml".
9215 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9216 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9217 * will be used to make the request.
9219 Roo.data.HttpProxy = function(conn){
9220 Roo.data.HttpProxy.superclass.constructor.call(this);
9221 // is conn a conn config or a real conn?
9223 this.useAjax = !conn || !conn.events;
9227 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9228 // thse are take from connection...
9231 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9234 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9235 * extra parameters to each request made by this object. (defaults to undefined)
9238 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9239 * to each request made by this object. (defaults to undefined)
9242 * @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)
9245 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9248 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9254 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9258 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9259 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9260 * a finer-grained basis than the DataProxy events.
9262 getConnection : function(){
9263 return this.useAjax ? Roo.Ajax : this.conn;
9267 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9268 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9269 * process that block using the passed callback.
9270 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9271 * for the request to the remote server.
9272 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9273 * object into a block of Roo.data.Records.
9274 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9275 * The function must be passed <ul>
9276 * <li>The Record block object</li>
9277 * <li>The "arg" argument from the load function</li>
9278 * <li>A boolean success indicator</li>
9280 * @param {Object} scope The scope in which to call the callback
9281 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9283 load : function(params, reader, callback, scope, arg){
9284 if(this.fireEvent("beforeload", this, params) !== false){
9286 params : params || {},
9288 callback : callback,
9293 callback : this.loadResponse,
9297 Roo.applyIf(o, this.conn);
9298 if(this.activeRequest){
9299 Roo.Ajax.abort(this.activeRequest);
9301 this.activeRequest = Roo.Ajax.request(o);
9303 this.conn.request(o);
9306 callback.call(scope||this, null, arg, false);
9311 loadResponse : function(o, success, response){
9312 delete this.activeRequest;
9314 this.fireEvent("loadexception", this, o, response);
9315 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9320 result = o.reader.read(response);
9322 this.fireEvent("loadexception", this, o, response, e);
9323 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9327 this.fireEvent("load", this, o, o.request.arg);
9328 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9332 update : function(dataSet){
9337 updateResponse : function(dataSet){
9342 * Ext JS Library 1.1.1
9343 * Copyright(c) 2006-2007, Ext JS, LLC.
9345 * Originally Released Under LGPL - original licence link has changed is not relivant.
9348 * <script type="text/javascript">
9352 * @class Roo.data.ScriptTagProxy
9353 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9354 * other than the originating domain of the running page.<br><br>
9356 * <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
9357 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9359 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9360 * source code that is used as the source inside a <script> tag.<br><br>
9362 * In order for the browser to process the returned data, the server must wrap the data object
9363 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9364 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9365 * depending on whether the callback name was passed:
9368 boolean scriptTag = false;
9369 String cb = request.getParameter("callback");
9372 response.setContentType("text/javascript");
9374 response.setContentType("application/x-json");
9376 Writer out = response.getWriter();
9378 out.write(cb + "(");
9380 out.print(dataBlock.toJsonString());
9387 * @param {Object} config A configuration object.
9389 Roo.data.ScriptTagProxy = function(config){
9390 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9391 Roo.apply(this, config);
9392 this.head = document.getElementsByTagName("head")[0];
9395 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9397 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9399 * @cfg {String} url The URL from which to request the data object.
9402 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9406 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9407 * the server the name of the callback function set up by the load call to process the returned data object.
9408 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9409 * javascript output which calls this named function passing the data object as its only parameter.
9411 callbackParam : "callback",
9413 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9414 * name to the request.
9419 * Load data from the configured URL, read the data object into
9420 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9421 * process that block using the passed callback.
9422 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9423 * for the request to the remote server.
9424 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9425 * object into a block of Roo.data.Records.
9426 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9427 * The function must be passed <ul>
9428 * <li>The Record block object</li>
9429 * <li>The "arg" argument from the load function</li>
9430 * <li>A boolean success indicator</li>
9432 * @param {Object} scope The scope in which to call the callback
9433 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9435 load : function(params, reader, callback, scope, arg){
9436 if(this.fireEvent("beforeload", this, params) !== false){
9438 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9441 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9443 url += "&_dc=" + (new Date().getTime());
9445 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9448 cb : "stcCallback"+transId,
9449 scriptId : "stcScript"+transId,
9453 callback : callback,
9459 window[trans.cb] = function(o){
9460 conn.handleResponse(o, trans);
9463 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9465 if(this.autoAbort !== false){
9469 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9471 var script = document.createElement("script");
9472 script.setAttribute("src", url);
9473 script.setAttribute("type", "text/javascript");
9474 script.setAttribute("id", trans.scriptId);
9475 this.head.appendChild(script);
9479 callback.call(scope||this, null, arg, false);
9484 isLoading : function(){
9485 return this.trans ? true : false;
9489 * Abort the current server request.
9492 if(this.isLoading()){
9493 this.destroyTrans(this.trans);
9498 destroyTrans : function(trans, isLoaded){
9499 this.head.removeChild(document.getElementById(trans.scriptId));
9500 clearTimeout(trans.timeoutId);
9502 window[trans.cb] = undefined;
9504 delete window[trans.cb];
9507 // if hasn't been loaded, wait for load to remove it to prevent script error
9508 window[trans.cb] = function(){
9509 window[trans.cb] = undefined;
9511 delete window[trans.cb];
9518 handleResponse : function(o, trans){
9520 this.destroyTrans(trans, true);
9523 result = trans.reader.readRecords(o);
9525 this.fireEvent("loadexception", this, o, trans.arg, e);
9526 trans.callback.call(trans.scope||window, null, trans.arg, false);
9529 this.fireEvent("load", this, o, trans.arg);
9530 trans.callback.call(trans.scope||window, result, trans.arg, true);
9534 handleFailure : function(trans){
9536 this.destroyTrans(trans, false);
9537 this.fireEvent("loadexception", this, null, trans.arg);
9538 trans.callback.call(trans.scope||window, null, trans.arg, false);
9542 * Ext JS Library 1.1.1
9543 * Copyright(c) 2006-2007, Ext JS, LLC.
9545 * Originally Released Under LGPL - original licence link has changed is not relivant.
9548 * <script type="text/javascript">
9552 * @class Roo.data.JsonReader
9553 * @extends Roo.data.DataReader
9554 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9555 * based on mappings in a provided Roo.data.Record constructor.
9557 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9558 * in the reply previously.
9563 var RecordDef = Roo.data.Record.create([
9564 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
9565 {name: 'occupation'} // This field will use "occupation" as the mapping.
9567 var myReader = new Roo.data.JsonReader({
9568 totalProperty: "results", // The property which contains the total dataset size (optional)
9569 root: "rows", // The property which contains an Array of row objects
9570 id: "id" // The property within each row object that provides an ID for the record (optional)
9574 * This would consume a JSON file like this:
9576 { 'results': 2, 'rows': [
9577 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9578 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9581 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9582 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9583 * paged from the remote server.
9584 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9585 * @cfg {String} root name of the property which contains the Array of row objects.
9586 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9588 * Create a new JsonReader
9589 * @param {Object} meta Metadata configuration options
9590 * @param {Object} recordType Either an Array of field definition objects,
9591 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9593 Roo.data.JsonReader = function(meta, recordType){
9596 // set some defaults:
9598 totalProperty: 'total',
9599 successProperty : 'success',
9604 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9606 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9609 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
9610 * Used by Store query builder to append _requestMeta to params.
9613 metaFromRemote : false,
9615 * This method is only used by a DataProxy which has retrieved data from a remote server.
9616 * @param {Object} response The XHR object which contains the JSON data in its responseText.
9617 * @return {Object} data A data block which is used by an Roo.data.Store object as
9618 * a cache of Roo.data.Records.
9620 read : function(response){
9621 var json = response.responseText;
9623 var o = /* eval:var:o */ eval("("+json+")");
9625 throw {message: "JsonReader.read: Json object not found"};
9631 this.metaFromRemote = true;
9632 this.meta = o.metaData;
9633 this.recordType = Roo.data.Record.create(o.metaData.fields);
9634 this.onMetaChange(this.meta, this.recordType, o);
9636 return this.readRecords(o);
9639 // private function a store will implement
9640 onMetaChange : function(meta, recordType, o){
9647 simpleAccess: function(obj, subsc) {
9654 getJsonAccessor: function(){
9656 return function(expr) {
9658 return(re.test(expr))
9659 ? new Function("obj", "return obj." + expr)
9669 * Create a data block containing Roo.data.Records from an XML document.
9670 * @param {Object} o An object which contains an Array of row objects in the property specified
9671 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
9672 * which contains the total size of the dataset.
9673 * @return {Object} data A data block which is used by an Roo.data.Store object as
9674 * a cache of Roo.data.Records.
9676 readRecords : function(o){
9678 * After any data loads, the raw JSON data is available for further custom processing.
9682 var s = this.meta, Record = this.recordType,
9683 f = Record.prototype.fields, fi = f.items, fl = f.length;
9685 // Generate extraction functions for the totalProperty, the root, the id, and for each field
9687 if(s.totalProperty) {
9688 this.getTotal = this.getJsonAccessor(s.totalProperty);
9690 if(s.successProperty) {
9691 this.getSuccess = this.getJsonAccessor(s.successProperty);
9693 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
9695 var g = this.getJsonAccessor(s.id);
9696 this.getId = function(rec) {
9698 return (r === undefined || r === "") ? null : r;
9701 this.getId = function(){return null;};
9704 for(var jj = 0; jj < fl; jj++){
9706 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
9707 this.ef[jj] = this.getJsonAccessor(map);
9711 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
9712 if(s.totalProperty){
9713 var vt = parseInt(this.getTotal(o), 10);
9718 if(s.successProperty){
9719 var vs = this.getSuccess(o);
9720 if(vs === false || vs === 'false'){
9725 for(var i = 0; i < c; i++){
9728 var id = this.getId(n);
9729 for(var j = 0; j < fl; j++){
9731 var v = this.ef[j](n);
9733 Roo.log('missing convert for ' + f.name);
9737 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
9739 var record = new Record(values, id);
9741 records[i] = record;
9747 totalRecords : totalRecords
9752 * Ext JS Library 1.1.1
9753 * Copyright(c) 2006-2007, Ext JS, LLC.
9755 * Originally Released Under LGPL - original licence link has changed is not relivant.
9758 * <script type="text/javascript">
9762 * @class Roo.data.ArrayReader
9763 * @extends Roo.data.DataReader
9764 * Data reader class to create an Array of Roo.data.Record objects from an Array.
9765 * Each element of that Array represents a row of data fields. The
9766 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
9767 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
9771 var RecordDef = Roo.data.Record.create([
9772 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
9773 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
9775 var myReader = new Roo.data.ArrayReader({
9776 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
9780 * This would consume an Array like this:
9782 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
9784 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
9786 * Create a new JsonReader
9787 * @param {Object} meta Metadata configuration options.
9788 * @param {Object} recordType Either an Array of field definition objects
9789 * as specified to {@link Roo.data.Record#create},
9790 * or an {@link Roo.data.Record} object
9791 * created using {@link Roo.data.Record#create}.
9793 Roo.data.ArrayReader = function(meta, recordType){
9794 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
9797 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
9799 * Create a data block containing Roo.data.Records from an XML document.
9800 * @param {Object} o An Array of row objects which represents the dataset.
9801 * @return {Object} data A data block which is used by an Roo.data.Store object as
9802 * a cache of Roo.data.Records.
9804 readRecords : function(o){
9805 var sid = this.meta ? this.meta.id : null;
9806 var recordType = this.recordType, fields = recordType.prototype.fields;
9809 for(var i = 0; i < root.length; i++){
9812 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
9813 for(var j = 0, jlen = fields.length; j < jlen; j++){
9814 var f = fields.items[j];
9815 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
9816 var v = n[k] !== undefined ? n[k] : f.defaultValue;
9820 var record = new recordType(values, id);
9822 records[records.length] = record;
9826 totalRecords : records.length
9835 * @class Roo.bootstrap.ComboBox
9836 * @extends Roo.bootstrap.TriggerField
9837 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
9838 * @cfg {Boolean} append (true|false) default false
9839 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
9840 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
9841 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
9843 * Create a new ComboBox.
9844 * @param {Object} config Configuration options
9846 Roo.bootstrap.ComboBox = function(config){
9847 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
9851 * Fires when the dropdown list is expanded
9852 * @param {Roo.bootstrap.ComboBox} combo This combo box
9857 * Fires when the dropdown list is collapsed
9858 * @param {Roo.bootstrap.ComboBox} combo This combo box
9862 * @event beforeselect
9863 * Fires before a list item is selected. Return false to cancel the selection.
9864 * @param {Roo.bootstrap.ComboBox} combo This combo box
9865 * @param {Roo.data.Record} record The data record returned from the underlying store
9866 * @param {Number} index The index of the selected item in the dropdown list
9868 'beforeselect' : true,
9871 * Fires when a list item is selected
9872 * @param {Roo.bootstrap.ComboBox} combo This combo box
9873 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
9874 * @param {Number} index The index of the selected item in the dropdown list
9878 * @event beforequery
9879 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
9880 * The event object passed has these properties:
9881 * @param {Roo.bootstrap.ComboBox} combo This combo box
9882 * @param {String} query The query
9883 * @param {Boolean} forceAll true to force "all" query
9884 * @param {Boolean} cancel true to cancel the query
9885 * @param {Object} e The query event object
9887 'beforequery': true,
9890 * Fires when the 'add' icon is pressed (add a listener to enable add button)
9891 * @param {Roo.bootstrap.ComboBox} combo This combo box
9896 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
9897 * @param {Roo.bootstrap.ComboBox} combo This combo box
9898 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
9903 * Fires when the remove value from the combobox array
9904 * @param {Roo.bootstrap.ComboBox} combo This combo box
9911 this.tickItems = [];
9913 this.selectedIndex = -1;
9914 if(this.mode == 'local'){
9915 if(config.queryDelay === undefined){
9916 this.queryDelay = 10;
9918 if(config.minChars === undefined){
9924 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
9927 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
9928 * rendering into an Roo.Editor, defaults to false)
9931 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
9932 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
9935 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
9938 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
9939 * the dropdown list (defaults to undefined, with no header element)
9943 * @cfg {String/Roo.Template} tpl The template to use to render the output
9947 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
9949 listWidth: undefined,
9951 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
9952 * mode = 'remote' or 'text' if mode = 'local')
9954 displayField: undefined,
9956 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
9957 * mode = 'remote' or 'value' if mode = 'local').
9958 * Note: use of a valueField requires the user make a selection
9959 * in order for a value to be mapped.
9961 valueField: undefined,
9965 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
9966 * field's data value (defaults to the underlying DOM element's name)
9968 hiddenName: undefined,
9970 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
9974 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
9976 selectedClass: 'active',
9979 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
9983 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
9984 * anchor positions (defaults to 'tl-bl')
9986 listAlign: 'tl-bl?',
9988 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
9992 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
9993 * query specified by the allQuery config option (defaults to 'query')
9995 triggerAction: 'query',
9997 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
9998 * (defaults to 4, does not apply if editable = false)
10002 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10003 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10007 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10008 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10012 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10013 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10017 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10018 * when editable = true (defaults to false)
10020 selectOnFocus:false,
10022 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10024 queryParam: 'query',
10026 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10027 * when mode = 'remote' (defaults to 'Loading...')
10029 loadingText: 'Loading...',
10031 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10035 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10039 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10040 * traditional select (defaults to true)
10044 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10048 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10052 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10053 * listWidth has a higher value)
10057 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10058 * allow the user to set arbitrary text into the field (defaults to false)
10060 forceSelection:false,
10062 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10063 * if typeAhead = true (defaults to 250)
10065 typeAheadDelay : 250,
10067 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10068 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10070 valueNotFoundText : undefined,
10072 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10074 blockFocus : false,
10077 * @cfg {Boolean} disableClear Disable showing of clear button.
10079 disableClear : false,
10081 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10083 alwaysQuery : false,
10086 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10100 btnPosition : 'right',
10102 // element that contains real text value.. (when hidden is used..)
10104 getAutoCreate : function()
10111 if(!this.tickable){
10112 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10117 * ComboBox with tickable selections
10120 var align = this.labelAlign || this.parentLabelAlign();
10123 cls : 'form-group roo-combobox-tickable' //input-group
10129 cls : 'tickable-buttons',
10134 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10141 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10148 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10155 Roo.each(buttons.cn, function(c){
10157 c.cls += ' btn-' + _this.size;
10160 if (_this.disabled) {
10171 cls: 'form-hidden-field'
10175 cls: 'select2-choices',
10179 cls: 'select2-search-field',
10191 cls: 'select2-container input-group select2-container-multi',
10196 cls: 'typeahead typeahead-long dropdown-menu',
10197 style: 'display:none; max-height:' + this.maxHeight + 'px;'
10202 if (align ==='left' && this.fieldLabel.length) {
10204 Roo.log("left and has label");
10210 cls : 'control-label col-sm-' + this.labelWidth,
10211 html : this.fieldLabel
10215 cls : "col-sm-" + (12 - this.labelWidth),
10222 } else if ( this.fieldLabel.length) {
10228 //cls : 'input-group-addon',
10229 html : this.fieldLabel
10239 Roo.log(" no label && no align");
10246 ['xs','sm','md','lg'].map(function(size){
10247 if (settings[size]) {
10248 cfg.cls += ' col-' + size + '-' + settings[size];
10257 initEvents: function()
10261 throw "can not find store for combo";
10263 this.store = Roo.factory(this.store, Roo.data);
10266 this.initTickableEvnets();
10270 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10273 if(this.hiddenName){
10275 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10277 this.hiddenField.dom.value =
10278 this.hiddenValue !== undefined ? this.hiddenValue :
10279 this.value !== undefined ? this.value : '';
10281 // prevent input submission
10282 this.el.dom.removeAttribute('name');
10283 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10288 // this.el.dom.setAttribute('autocomplete', 'off');
10291 var cls = 'x-combo-list';
10292 this.list = this.el.select('ul.dropdown-menu',true).first();
10294 //this.list = new Roo.Layer({
10295 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10301 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10302 _this.list.setWidth(lw);
10305 this.list.on('mouseover', this.onViewOver, this);
10306 this.list.on('mousemove', this.onViewMove, this);
10308 this.list.on('scroll', this.onViewScroll, this);
10311 this.list.swallowEvent('mousewheel');
10312 this.assetHeight = 0;
10315 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10316 this.assetHeight += this.header.getHeight();
10319 this.innerList = this.list.createChild({cls:cls+'-inner'});
10320 this.innerList.on('mouseover', this.onViewOver, this);
10321 this.innerList.on('mousemove', this.onViewMove, this);
10322 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10324 if(this.allowBlank && !this.pageSize && !this.disableClear){
10325 this.footer = this.list.createChild({cls:cls+'-ft'});
10326 this.pageTb = new Roo.Toolbar(this.footer);
10330 this.footer = this.list.createChild({cls:cls+'-ft'});
10331 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10332 {pageSize: this.pageSize});
10336 if (this.pageTb && this.allowBlank && !this.disableClear) {
10338 this.pageTb.add(new Roo.Toolbar.Fill(), {
10339 cls: 'x-btn-icon x-btn-clear',
10341 handler: function()
10344 _this.clearValue();
10345 _this.onSelect(false, -1);
10350 this.assetHeight += this.footer.getHeight();
10355 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10358 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
10359 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10361 //this.view.wrapEl.setDisplayed(false);
10362 this.view.on('click', this.onViewClick, this);
10366 this.store.on('beforeload', this.onBeforeLoad, this);
10367 this.store.on('load', this.onLoad, this);
10368 this.store.on('loadexception', this.onLoadException, this);
10370 if(this.resizable){
10371 this.resizer = new Roo.Resizable(this.list, {
10372 pinned:true, handles:'se'
10374 this.resizer.on('resize', function(r, w, h){
10375 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10376 this.listWidth = w;
10377 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10378 this.restrictHeight();
10380 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10383 if(!this.editable){
10384 this.editable = true;
10385 this.setEditable(false);
10390 if (typeof(this.events.add.listeners) != 'undefined') {
10392 this.addicon = this.wrap.createChild(
10393 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10395 this.addicon.on('click', function(e) {
10396 this.fireEvent('add', this);
10399 if (typeof(this.events.edit.listeners) != 'undefined') {
10401 this.editicon = this.wrap.createChild(
10402 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10403 if (this.addicon) {
10404 this.editicon.setStyle('margin-left', '40px');
10406 this.editicon.on('click', function(e) {
10408 // we fire even if inothing is selected..
10409 this.fireEvent('edit', this, this.lastData );
10415 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10416 "up" : function(e){
10417 this.inKeyMode = true;
10421 "down" : function(e){
10422 if(!this.isExpanded()){
10423 this.onTriggerClick();
10425 this.inKeyMode = true;
10430 "enter" : function(e){
10431 // this.onViewClick();
10435 if(this.fireEvent("specialkey", this, e)){
10436 this.onViewClick(false);
10442 "esc" : function(e){
10446 "tab" : function(e){
10449 if(this.fireEvent("specialkey", this, e)){
10450 this.onViewClick(false);
10458 doRelay : function(foo, bar, hname){
10459 if(hname == 'down' || this.scope.isExpanded()){
10460 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10469 this.queryDelay = Math.max(this.queryDelay || 10,
10470 this.mode == 'local' ? 10 : 250);
10473 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10475 if(this.typeAhead){
10476 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10478 if(this.editable !== false){
10479 this.inputEl().on("keyup", this.onKeyUp, this);
10481 if(this.forceSelection){
10482 this.inputEl().on('blur', this.doForce, this);
10486 this.choices = this.el.select('ul.select2-choices', true).first();
10487 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10491 initTickableEvnets: function()
10493 if(this.hiddenName){
10495 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10497 this.hiddenField.dom.value =
10498 this.hiddenValue !== undefined ? this.hiddenValue :
10499 this.value !== undefined ? this.value : '';
10501 // prevent input submission
10502 this.el.dom.removeAttribute('name');
10503 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10508 this.list = this.el.select('ul.dropdown-menu',true).first();
10510 this.choices = this.el.select('ul.select2-choices', true).first();
10511 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10513 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10514 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10516 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10517 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10519 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10520 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10522 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10523 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10524 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10527 this.cancelBtn.hide();
10532 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10533 _this.list.setWidth(lw);
10536 this.list.on('mouseover', this.onViewOver, this);
10537 this.list.on('mousemove', this.onViewMove, this);
10539 this.list.on('scroll', this.onViewScroll, this);
10542 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>';
10545 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
10546 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10549 //this.view.wrapEl.setDisplayed(false);
10550 this.view.on('click', this.onViewClick, this);
10554 this.store.on('beforeload', this.onBeforeLoad, this);
10555 this.store.on('load', this.onLoad, this);
10556 this.store.on('loadexception', this.onLoadException, this);
10558 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
10559 // "up" : function(e){
10560 // this.inKeyMode = true;
10561 // this.selectPrev();
10564 // "down" : function(e){
10565 // if(!this.isExpanded()){
10566 // this.onTriggerClick();
10568 // this.inKeyMode = true;
10569 // this.selectNext();
10573 // "enter" : function(e){
10574 //// this.onViewClick();
10576 // this.collapse();
10578 // if(this.fireEvent("specialkey", this, e)){
10579 // this.onViewClick(false);
10585 // "esc" : function(e){
10586 // this.collapse();
10589 // "tab" : function(e){
10590 // this.collapse();
10592 // if(this.fireEvent("specialkey", this, e)){
10593 // this.onViewClick(false);
10601 // doRelay : function(foo, bar, hname){
10602 // if(hname == 'down' || this.scope.isExpanded()){
10603 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10608 // forceKeyDown: true
10612 this.queryDelay = Math.max(this.queryDelay || 10,
10613 this.mode == 'local' ? 10 : 250);
10616 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10618 if(this.typeAhead){
10619 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10623 onDestroy : function(){
10625 this.view.setStore(null);
10626 this.view.el.removeAllListeners();
10627 this.view.el.remove();
10628 this.view.purgeListeners();
10631 this.list.dom.innerHTML = '';
10635 this.store.un('beforeload', this.onBeforeLoad, this);
10636 this.store.un('load', this.onLoad, this);
10637 this.store.un('loadexception', this.onLoadException, this);
10639 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
10643 fireKey : function(e){
10644 if(e.isNavKeyPress() && !this.list.isVisible()){
10645 this.fireEvent("specialkey", this, e);
10650 onResize: function(w, h){
10651 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
10653 // if(typeof w != 'number'){
10654 // // we do not handle it!?!?
10657 // var tw = this.trigger.getWidth();
10658 // // tw += this.addicon ? this.addicon.getWidth() : 0;
10659 // // tw += this.editicon ? this.editicon.getWidth() : 0;
10661 // this.inputEl().setWidth( this.adjustWidth('input', x));
10663 // //this.trigger.setStyle('left', x+'px');
10665 // if(this.list && this.listWidth === undefined){
10666 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
10667 // this.list.setWidth(lw);
10668 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10676 * Allow or prevent the user from directly editing the field text. If false is passed,
10677 * the user will only be able to select from the items defined in the dropdown list. This method
10678 * is the runtime equivalent of setting the 'editable' config option at config time.
10679 * @param {Boolean} value True to allow the user to directly edit the field text
10681 setEditable : function(value){
10682 if(value == this.editable){
10685 this.editable = value;
10687 this.inputEl().dom.setAttribute('readOnly', true);
10688 this.inputEl().on('mousedown', this.onTriggerClick, this);
10689 this.inputEl().addClass('x-combo-noedit');
10691 this.inputEl().dom.setAttribute('readOnly', false);
10692 this.inputEl().un('mousedown', this.onTriggerClick, this);
10693 this.inputEl().removeClass('x-combo-noedit');
10699 onBeforeLoad : function(combo,opts){
10700 if(!this.hasFocus){
10704 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
10706 this.restrictHeight();
10707 this.selectedIndex = -1;
10711 onLoad : function(){
10713 this.hasQuery = false;
10715 if(!this.hasFocus){
10719 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10720 this.loading.hide();
10723 if(this.store.getCount() > 0){
10725 this.restrictHeight();
10726 if(this.lastQuery == this.allQuery){
10727 if(this.editable && !this.tickable){
10728 this.inputEl().dom.select();
10730 if(!this.selectByValue(this.value, true) && this.autoFocus){
10731 this.select(0, true);
10734 if(this.autoFocus){
10737 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
10738 this.taTask.delay(this.typeAheadDelay);
10742 this.onEmptyResults();
10748 onLoadException : function()
10750 this.hasQuery = false;
10752 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10753 this.loading.hide();
10757 Roo.log(this.store.reader.jsonData);
10758 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
10760 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
10766 onTypeAhead : function(){
10767 if(this.store.getCount() > 0){
10768 var r = this.store.getAt(0);
10769 var newValue = r.data[this.displayField];
10770 var len = newValue.length;
10771 var selStart = this.getRawValue().length;
10773 if(selStart != len){
10774 this.setRawValue(newValue);
10775 this.selectText(selStart, newValue.length);
10781 onSelect : function(record, index){
10783 if(this.fireEvent('beforeselect', this, record, index) !== false){
10785 this.setFromData(index > -1 ? record.data : false);
10788 this.fireEvent('select', this, record, index);
10793 * Returns the currently selected field value or empty string if no value is set.
10794 * @return {String} value The selected value
10796 getValue : function(){
10799 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
10802 if(this.valueField){
10803 return typeof this.value != 'undefined' ? this.value : '';
10805 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
10810 * Clears any text/value currently set in the field
10812 clearValue : function(){
10813 if(this.hiddenField){
10814 this.hiddenField.dom.value = '';
10817 this.setRawValue('');
10818 this.lastSelectionText = '';
10823 * Sets the specified value into the field. If the value finds a match, the corresponding record text
10824 * will be displayed in the field. If the value does not match the data value of an existing item,
10825 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
10826 * Otherwise the field will be blank (although the value will still be set).
10827 * @param {String} value The value to match
10829 setValue : function(v){
10836 if(this.valueField){
10837 var r = this.findRecord(this.valueField, v);
10839 text = r.data[this.displayField];
10840 }else if(this.valueNotFoundText !== undefined){
10841 text = this.valueNotFoundText;
10844 this.lastSelectionText = text;
10845 if(this.hiddenField){
10846 this.hiddenField.dom.value = v;
10848 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
10852 * @property {Object} the last set data for the element
10857 * Sets the value of the field based on a object which is related to the record format for the store.
10858 * @param {Object} value the value to set as. or false on reset?
10860 setFromData : function(o){
10867 var dv = ''; // display value
10868 var vv = ''; // value value..
10870 if (this.displayField) {
10871 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
10873 // this is an error condition!!!
10874 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
10877 if(this.valueField){
10878 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
10881 if(this.hiddenField){
10882 this.hiddenField.dom.value = vv;
10884 this.lastSelectionText = dv;
10885 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
10889 // no hidden field.. - we store the value in 'value', but still display
10890 // display field!!!!
10891 this.lastSelectionText = dv;
10892 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
10898 reset : function(){
10899 // overridden so that last data is reset..
10900 this.setValue(this.originalValue);
10901 this.clearInvalid();
10902 this.lastData = false;
10904 this.view.clearSelections();
10908 findRecord : function(prop, value){
10910 if(this.store.getCount() > 0){
10911 this.store.each(function(r){
10912 if(r.data[prop] == value){
10922 getName: function()
10924 // returns hidden if it's set..
10925 if (!this.rendered) {return ''};
10926 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
10930 onViewMove : function(e, t){
10931 this.inKeyMode = false;
10935 onViewOver : function(e, t){
10936 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
10939 var item = this.view.findItemFromChild(t);
10942 var index = this.view.indexOf(item);
10943 this.select(index, false);
10948 onViewClick : function(view, doFocus, el, e)
10950 var index = this.view.getSelectedIndexes()[0];
10952 var r = this.store.getAt(index);
10956 if(e.getTarget().nodeName.toLowerCase() != 'input'){
10963 Roo.each(this.tickItems, function(v,k){
10965 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
10966 _this.tickItems.splice(k, 1);
10976 this.tickItems.push(r.data);
10981 this.onSelect(r, index);
10983 if(doFocus !== false && !this.blockFocus){
10984 this.inputEl().focus();
10989 restrictHeight : function(){
10990 //this.innerList.dom.style.height = '';
10991 //var inner = this.innerList.dom;
10992 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
10993 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
10994 //this.list.beginUpdate();
10995 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
10996 this.list.alignTo(this.inputEl(), this.listAlign);
10997 //this.list.endUpdate();
11001 onEmptyResults : function(){
11006 * Returns true if the dropdown list is expanded, else false.
11008 isExpanded : function(){
11009 return this.list.isVisible();
11013 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11014 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11015 * @param {String} value The data value of the item to select
11016 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11017 * selected item if it is not currently in view (defaults to true)
11018 * @return {Boolean} True if the value matched an item in the list, else false
11020 selectByValue : function(v, scrollIntoView){
11021 if(v !== undefined && v !== null){
11022 var r = this.findRecord(this.valueField || this.displayField, v);
11024 this.select(this.store.indexOf(r), scrollIntoView);
11032 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11033 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11034 * @param {Number} index The zero-based index of the list item to select
11035 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11036 * selected item if it is not currently in view (defaults to true)
11038 select : function(index, scrollIntoView){
11039 this.selectedIndex = index;
11040 this.view.select(index);
11041 if(scrollIntoView !== false){
11042 var el = this.view.getNode(index);
11044 //this.innerList.scrollChildIntoView(el, false);
11051 selectNext : function(){
11052 var ct = this.store.getCount();
11054 if(this.selectedIndex == -1){
11056 }else if(this.selectedIndex < ct-1){
11057 this.select(this.selectedIndex+1);
11063 selectPrev : function(){
11064 var ct = this.store.getCount();
11066 if(this.selectedIndex == -1){
11068 }else if(this.selectedIndex != 0){
11069 this.select(this.selectedIndex-1);
11075 onKeyUp : function(e){
11076 if(this.editable !== false && !e.isSpecialKey()){
11077 this.lastKey = e.getKey();
11078 this.dqTask.delay(this.queryDelay);
11083 validateBlur : function(){
11084 return !this.list || !this.list.isVisible();
11088 initQuery : function(){
11089 this.doQuery(this.getRawValue());
11093 doForce : function(){
11094 if(this.inputEl().dom.value.length > 0){
11095 this.inputEl().dom.value =
11096 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11102 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11103 * query allowing the query action to be canceled if needed.
11104 * @param {String} query The SQL query to execute
11105 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11106 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11107 * saved in the current store (defaults to false)
11109 doQuery : function(q, forceAll){
11111 if(q === undefined || q === null){
11116 forceAll: forceAll,
11120 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11125 forceAll = qe.forceAll;
11126 if(forceAll === true || (q.length >= this.minChars)){
11128 this.hasQuery = true;
11130 if(this.lastQuery != q || this.alwaysQuery){
11131 this.lastQuery = q;
11132 if(this.mode == 'local'){
11133 this.selectedIndex = -1;
11135 this.store.clearFilter();
11137 this.store.filter(this.displayField, q);
11141 this.store.baseParams[this.queryParam] = q;
11143 var options = {params : this.getParams(q)};
11146 options.add = true;
11147 options.params.start = this.page * this.pageSize;
11150 this.store.load(options);
11152 * this code will make the page width larger, at the beginning, the list not align correctly,
11153 * we should expand the list on onLoad
11154 * so command out it
11159 this.selectedIndex = -1;
11164 this.loadNext = false;
11168 getParams : function(q){
11170 //p[this.queryParam] = q;
11174 p.limit = this.pageSize;
11180 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11182 collapse : function(){
11183 if(!this.isExpanded()){
11191 this.cancelBtn.hide();
11192 this.trigger.show();
11195 Roo.get(document).un('mousedown', this.collapseIf, this);
11196 Roo.get(document).un('mousewheel', this.collapseIf, this);
11197 if (!this.editable) {
11198 Roo.get(document).un('keydown', this.listKeyPress, this);
11200 this.fireEvent('collapse', this);
11204 collapseIf : function(e){
11205 var in_combo = e.within(this.el);
11206 var in_list = e.within(this.list);
11208 if (in_combo || in_list) {
11209 //e.stopPropagation();
11214 this.onTickableFooterButtonClick(e, false, false);
11222 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11224 expand : function(){
11226 if(this.isExpanded() || !this.hasFocus){
11230 this.list.alignTo(this.inputEl(), this.listAlign);
11235 this.tickItems = Roo.apply([], this.item);
11238 this.cancelBtn.show();
11239 this.trigger.hide();
11243 Roo.get(document).on('mousedown', this.collapseIf, this);
11244 Roo.get(document).on('mousewheel', this.collapseIf, this);
11245 if (!this.editable) {
11246 Roo.get(document).on('keydown', this.listKeyPress, this);
11249 this.fireEvent('expand', this);
11253 // Implements the default empty TriggerField.onTriggerClick function
11254 onTriggerClick : function()
11256 Roo.log('trigger click');
11263 this.onTickableTriggerClick();
11268 this.loadNext = false;
11270 if(this.isExpanded()){
11272 if (!this.blockFocus) {
11273 this.inputEl().focus();
11277 this.hasFocus = true;
11278 if(this.triggerAction == 'all') {
11279 this.doQuery(this.allQuery, true);
11281 this.doQuery(this.getRawValue());
11283 if (!this.blockFocus) {
11284 this.inputEl().focus();
11289 onTickableTriggerClick : function()
11292 this.loadNext = false;
11293 this.hasFocus = true;
11295 if(this.triggerAction == 'all') {
11296 this.doQuery(this.allQuery, true);
11298 this.doQuery(this.getRawValue());
11302 listKeyPress : function(e)
11304 //Roo.log('listkeypress');
11305 // scroll to first matching element based on key pres..
11306 if (e.isSpecialKey()) {
11309 var k = String.fromCharCode(e.getKey()).toUpperCase();
11312 var csel = this.view.getSelectedNodes();
11313 var cselitem = false;
11315 var ix = this.view.indexOf(csel[0]);
11316 cselitem = this.store.getAt(ix);
11317 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11323 this.store.each(function(v) {
11325 // start at existing selection.
11326 if (cselitem.id == v.id) {
11332 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11333 match = this.store.indexOf(v);
11339 if (match === false) {
11340 return true; // no more action?
11343 this.view.select(match);
11344 var sn = Roo.get(this.view.getSelectedNodes()[0])
11345 //sn.scrollIntoView(sn.dom.parentNode, false);
11348 onViewScroll : function(e, t){
11350 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
11354 this.hasQuery = true;
11356 this.loading = this.list.select('.loading', true).first();
11358 if(this.loading === null){
11359 this.list.createChild({
11361 cls: 'loading select2-more-results select2-active',
11362 html: 'Loading more results...'
11365 this.loading = this.list.select('.loading', true).first();
11367 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11369 this.loading.hide();
11372 this.loading.show();
11377 this.loadNext = true;
11379 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11384 addItem : function(o)
11386 var dv = ''; // display value
11388 if (this.displayField) {
11389 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11391 // this is an error condition!!!
11392 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11399 var choice = this.choices.createChild({
11401 cls: 'select2-search-choice',
11410 cls: 'select2-search-choice-close',
11415 }, this.searchField);
11417 var close = choice.select('a.select2-search-choice-close', true).first()
11419 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11427 this.inputEl().dom.value = '';
11431 onRemoveItem : function(e, _self, o)
11433 e.preventDefault();
11434 var index = this.item.indexOf(o.data) * 1;
11437 Roo.log('not this item?!');
11441 this.item.splice(index, 1);
11446 this.fireEvent('remove', this, e);
11450 syncValue : function()
11452 if(!this.item.length){
11459 Roo.each(this.item, function(i){
11460 if(_this.valueField){
11461 value.push(i[_this.valueField]);
11468 this.value = value.join(',');
11470 if(this.hiddenField){
11471 this.hiddenField.dom.value = this.value;
11475 clearItem : function()
11477 if(!this.multiple){
11483 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11490 inputEl: function ()
11493 return this.searchField;
11495 return this.el.select('input.form-control',true).first();
11499 onTickableFooterButtonClick : function(e, btn, el)
11501 e.preventDefault();
11503 if(btn && btn.name == 'cancel'){
11504 this.tickItems = Roo.apply([], this.item);
11513 Roo.each(this.tickItems, function(o){
11524 * @cfg {Boolean} grow
11528 * @cfg {Number} growMin
11532 * @cfg {Number} growMax
11542 * Ext JS Library 1.1.1
11543 * Copyright(c) 2006-2007, Ext JS, LLC.
11545 * Originally Released Under LGPL - original licence link has changed is not relivant.
11548 * <script type="text/javascript">
11553 * @extends Roo.util.Observable
11554 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11555 * This class also supports single and multi selection modes. <br>
11556 * Create a data model bound view:
11558 var store = new Roo.data.Store(...);
11560 var view = new Roo.View({
11562 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11564 singleSelect: true,
11565 selectedClass: "ydataview-selected",
11569 // listen for node click?
11570 view.on("click", function(vw, index, node, e){
11571 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
11575 dataModel.load("foobar.xml");
11577 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
11579 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
11580 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
11582 * Note: old style constructor is still suported (container, template, config)
11585 * Create a new View
11586 * @param {Object} config The config object
11589 Roo.View = function(config, depreciated_tpl, depreciated_config){
11591 this.parent = false;
11593 if (typeof(depreciated_tpl) == 'undefined') {
11594 // new way.. - universal constructor.
11595 Roo.apply(this, config);
11596 this.el = Roo.get(this.el);
11599 this.el = Roo.get(config);
11600 this.tpl = depreciated_tpl;
11601 Roo.apply(this, depreciated_config);
11603 this.wrapEl = this.el.wrap().wrap();
11604 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
11607 if(typeof(this.tpl) == "string"){
11608 this.tpl = new Roo.Template(this.tpl);
11610 // support xtype ctors..
11611 this.tpl = new Roo.factory(this.tpl, Roo);
11615 this.tpl.compile();
11620 * @event beforeclick
11621 * Fires before a click is processed. Returns false to cancel the default action.
11622 * @param {Roo.View} this
11623 * @param {Number} index The index of the target node
11624 * @param {HTMLElement} node The target node
11625 * @param {Roo.EventObject} e The raw event object
11627 "beforeclick" : true,
11630 * Fires when a template node is clicked.
11631 * @param {Roo.View} this
11632 * @param {Number} index The index of the target node
11633 * @param {HTMLElement} node The target node
11634 * @param {Roo.EventObject} e The raw event object
11639 * Fires when a template node is double clicked.
11640 * @param {Roo.View} this
11641 * @param {Number} index The index of the target node
11642 * @param {HTMLElement} node The target node
11643 * @param {Roo.EventObject} e The raw event object
11647 * @event contextmenu
11648 * Fires when a template node is right clicked.
11649 * @param {Roo.View} this
11650 * @param {Number} index The index of the target node
11651 * @param {HTMLElement} node The target node
11652 * @param {Roo.EventObject} e The raw event object
11654 "contextmenu" : true,
11656 * @event selectionchange
11657 * Fires when the selected nodes change.
11658 * @param {Roo.View} this
11659 * @param {Array} selections Array of the selected nodes
11661 "selectionchange" : true,
11664 * @event beforeselect
11665 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
11666 * @param {Roo.View} this
11667 * @param {HTMLElement} node The node to be selected
11668 * @param {Array} selections Array of currently selected nodes
11670 "beforeselect" : true,
11672 * @event preparedata
11673 * Fires on every row to render, to allow you to change the data.
11674 * @param {Roo.View} this
11675 * @param {Object} data to be rendered (change this)
11677 "preparedata" : true
11685 "click": this.onClick,
11686 "dblclick": this.onDblClick,
11687 "contextmenu": this.onContextMenu,
11691 this.selections = [];
11693 this.cmp = new Roo.CompositeElementLite([]);
11695 this.store = Roo.factory(this.store, Roo.data);
11696 this.setStore(this.store, true);
11699 if ( this.footer && this.footer.xtype) {
11701 var fctr = this.wrapEl.appendChild(document.createElement("div"));
11703 this.footer.dataSource = this.store
11704 this.footer.container = fctr;
11705 this.footer = Roo.factory(this.footer, Roo);
11706 fctr.insertFirst(this.el);
11708 // this is a bit insane - as the paging toolbar seems to detach the el..
11709 // dom.parentNode.parentNode.parentNode
11710 // they get detached?
11714 Roo.View.superclass.constructor.call(this);
11719 Roo.extend(Roo.View, Roo.util.Observable, {
11722 * @cfg {Roo.data.Store} store Data store to load data from.
11727 * @cfg {String|Roo.Element} el The container element.
11732 * @cfg {String|Roo.Template} tpl The template used by this View
11736 * @cfg {String} dataName the named area of the template to use as the data area
11737 * Works with domtemplates roo-name="name"
11741 * @cfg {String} selectedClass The css class to add to selected nodes
11743 selectedClass : "x-view-selected",
11745 * @cfg {String} emptyText The empty text to show when nothing is loaded.
11750 * @cfg {String} text to display on mask (default Loading)
11754 * @cfg {Boolean} multiSelect Allow multiple selection
11756 multiSelect : false,
11758 * @cfg {Boolean} singleSelect Allow single selection
11760 singleSelect: false,
11763 * @cfg {Boolean} toggleSelect - selecting
11765 toggleSelect : false,
11768 * @cfg {Boolean} tickable - selecting
11773 * Returns the element this view is bound to.
11774 * @return {Roo.Element}
11776 getEl : function(){
11777 return this.wrapEl;
11783 * Refreshes the view. - called by datachanged on the store. - do not call directly.
11785 refresh : function(){
11786 Roo.log('refresh');
11789 // if we are using something like 'domtemplate', then
11790 // the what gets used is:
11791 // t.applySubtemplate(NAME, data, wrapping data..)
11792 // the outer template then get' applied with
11793 // the store 'extra data'
11794 // and the body get's added to the
11795 // roo-name="data" node?
11796 // <span class='roo-tpl-{name}'></span> ?????
11800 this.clearSelections();
11801 this.el.update("");
11803 var records = this.store.getRange();
11804 if(records.length < 1) {
11806 // is this valid?? = should it render a template??
11808 this.el.update(this.emptyText);
11812 if (this.dataName) {
11813 this.el.update(t.apply(this.store.meta)); //????
11814 el = this.el.child('.roo-tpl-' + this.dataName);
11817 for(var i = 0, len = records.length; i < len; i++){
11818 var data = this.prepareData(records[i].data, i, records[i]);
11819 this.fireEvent("preparedata", this, data, i, records[i]);
11821 var d = Roo.apply({}, data);
11824 Roo.apply(d, {'roo-id' : Roo.id()});
11828 Roo.each(this.parent.item, function(item){
11829 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
11832 Roo.apply(d, {'roo-data-checked' : 'checked'});
11836 html[html.length] = Roo.util.Format.trim(
11838 t.applySubtemplate(this.dataName, d, this.store.meta) :
11845 el.update(html.join(""));
11846 this.nodes = el.dom.childNodes;
11847 this.updateIndexes(0);
11852 * Function to override to reformat the data that is sent to
11853 * the template for each node.
11854 * DEPRICATED - use the preparedata event handler.
11855 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
11856 * a JSON object for an UpdateManager bound view).
11858 prepareData : function(data, index, record)
11860 this.fireEvent("preparedata", this, data, index, record);
11864 onUpdate : function(ds, record){
11865 Roo.log('on update');
11866 this.clearSelections();
11867 var index = this.store.indexOf(record);
11868 var n = this.nodes[index];
11869 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
11870 n.parentNode.removeChild(n);
11871 this.updateIndexes(index, index);
11877 onAdd : function(ds, records, index)
11879 Roo.log(['on Add', ds, records, index] );
11880 this.clearSelections();
11881 if(this.nodes.length == 0){
11885 var n = this.nodes[index];
11886 for(var i = 0, len = records.length; i < len; i++){
11887 var d = this.prepareData(records[i].data, i, records[i]);
11889 this.tpl.insertBefore(n, d);
11892 this.tpl.append(this.el, d);
11895 this.updateIndexes(index);
11898 onRemove : function(ds, record, index){
11899 Roo.log('onRemove');
11900 this.clearSelections();
11901 var el = this.dataName ?
11902 this.el.child('.roo-tpl-' + this.dataName) :
11905 el.dom.removeChild(this.nodes[index]);
11906 this.updateIndexes(index);
11910 * Refresh an individual node.
11911 * @param {Number} index
11913 refreshNode : function(index){
11914 this.onUpdate(this.store, this.store.getAt(index));
11917 updateIndexes : function(startIndex, endIndex){
11918 var ns = this.nodes;
11919 startIndex = startIndex || 0;
11920 endIndex = endIndex || ns.length - 1;
11921 for(var i = startIndex; i <= endIndex; i++){
11922 ns[i].nodeIndex = i;
11927 * Changes the data store this view uses and refresh the view.
11928 * @param {Store} store
11930 setStore : function(store, initial){
11931 if(!initial && this.store){
11932 this.store.un("datachanged", this.refresh);
11933 this.store.un("add", this.onAdd);
11934 this.store.un("remove", this.onRemove);
11935 this.store.un("update", this.onUpdate);
11936 this.store.un("clear", this.refresh);
11937 this.store.un("beforeload", this.onBeforeLoad);
11938 this.store.un("load", this.onLoad);
11939 this.store.un("loadexception", this.onLoad);
11943 store.on("datachanged", this.refresh, this);
11944 store.on("add", this.onAdd, this);
11945 store.on("remove", this.onRemove, this);
11946 store.on("update", this.onUpdate, this);
11947 store.on("clear", this.refresh, this);
11948 store.on("beforeload", this.onBeforeLoad, this);
11949 store.on("load", this.onLoad, this);
11950 store.on("loadexception", this.onLoad, this);
11958 * onbeforeLoad - masks the loading area.
11961 onBeforeLoad : function(store,opts)
11963 Roo.log('onBeforeLoad');
11965 this.el.update("");
11967 this.el.mask(this.mask ? this.mask : "Loading" );
11969 onLoad : function ()
11976 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
11977 * @param {HTMLElement} node
11978 * @return {HTMLElement} The template node
11980 findItemFromChild : function(node){
11981 var el = this.dataName ?
11982 this.el.child('.roo-tpl-' + this.dataName,true) :
11985 if(!node || node.parentNode == el){
11988 var p = node.parentNode;
11989 while(p && p != el){
11990 if(p.parentNode == el){
11999 onClick : function(e){
12000 var item = this.findItemFromChild(e.getTarget());
12002 var index = this.indexOf(item);
12003 if(this.onItemClick(item, index, e) !== false){
12004 this.fireEvent("click", this, index, item, e);
12007 this.clearSelections();
12012 onContextMenu : function(e){
12013 var item = this.findItemFromChild(e.getTarget());
12015 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12020 onDblClick : function(e){
12021 var item = this.findItemFromChild(e.getTarget());
12023 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12027 onItemClick : function(item, index, e)
12029 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12032 if (this.toggleSelect) {
12033 var m = this.isSelected(item) ? 'unselect' : 'select';
12036 _t[m](item, true, false);
12039 if(this.multiSelect || this.singleSelect){
12040 if(this.multiSelect && e.shiftKey && this.lastSelection){
12041 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12043 this.select(item, this.multiSelect && e.ctrlKey);
12044 this.lastSelection = item;
12047 if(!this.tickable){
12048 e.preventDefault();
12056 * Get the number of selected nodes.
12059 getSelectionCount : function(){
12060 return this.selections.length;
12064 * Get the currently selected nodes.
12065 * @return {Array} An array of HTMLElements
12067 getSelectedNodes : function(){
12068 return this.selections;
12072 * Get the indexes of the selected nodes.
12075 getSelectedIndexes : function(){
12076 var indexes = [], s = this.selections;
12077 for(var i = 0, len = s.length; i < len; i++){
12078 indexes.push(s[i].nodeIndex);
12084 * Clear all selections
12085 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12087 clearSelections : function(suppressEvent){
12088 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12089 this.cmp.elements = this.selections;
12090 this.cmp.removeClass(this.selectedClass);
12091 this.selections = [];
12092 if(!suppressEvent){
12093 this.fireEvent("selectionchange", this, this.selections);
12099 * Returns true if the passed node is selected
12100 * @param {HTMLElement/Number} node The node or node index
12101 * @return {Boolean}
12103 isSelected : function(node){
12104 var s = this.selections;
12108 node = this.getNode(node);
12109 return s.indexOf(node) !== -1;
12114 * @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
12115 * @param {Boolean} keepExisting (optional) true to keep existing selections
12116 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12118 select : function(nodeInfo, keepExisting, suppressEvent){
12119 if(nodeInfo instanceof Array){
12121 this.clearSelections(true);
12123 for(var i = 0, len = nodeInfo.length; i < len; i++){
12124 this.select(nodeInfo[i], true, true);
12128 var node = this.getNode(nodeInfo);
12129 if(!node || this.isSelected(node)){
12130 return; // already selected.
12133 this.clearSelections(true);
12135 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12136 Roo.fly(node).addClass(this.selectedClass);
12137 this.selections.push(node);
12138 if(!suppressEvent){
12139 this.fireEvent("selectionchange", this, this.selections);
12147 * @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
12148 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12149 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12151 unselect : function(nodeInfo, keepExisting, suppressEvent)
12153 if(nodeInfo instanceof Array){
12154 Roo.each(this.selections, function(s) {
12155 this.unselect(s, nodeInfo);
12159 var node = this.getNode(nodeInfo);
12160 if(!node || !this.isSelected(node)){
12161 Roo.log("not selected");
12162 return; // not selected.
12166 Roo.each(this.selections, function(s) {
12168 Roo.fly(node).removeClass(this.selectedClass);
12175 this.selections= ns;
12176 this.fireEvent("selectionchange", this, this.selections);
12180 * Gets a template node.
12181 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12182 * @return {HTMLElement} The node or null if it wasn't found
12184 getNode : function(nodeInfo){
12185 if(typeof nodeInfo == "string"){
12186 return document.getElementById(nodeInfo);
12187 }else if(typeof nodeInfo == "number"){
12188 return this.nodes[nodeInfo];
12194 * Gets a range template nodes.
12195 * @param {Number} startIndex
12196 * @param {Number} endIndex
12197 * @return {Array} An array of nodes
12199 getNodes : function(start, end){
12200 var ns = this.nodes;
12201 start = start || 0;
12202 end = typeof end == "undefined" ? ns.length - 1 : end;
12205 for(var i = start; i <= end; i++){
12209 for(var i = start; i >= end; i--){
12217 * Finds the index of the passed node
12218 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12219 * @return {Number} The index of the node or -1
12221 indexOf : function(node){
12222 node = this.getNode(node);
12223 if(typeof node.nodeIndex == "number"){
12224 return node.nodeIndex;
12226 var ns = this.nodes;
12227 for(var i = 0, len = ns.length; i < len; i++){
12238 * based on jquery fullcalendar
12242 Roo.bootstrap = Roo.bootstrap || {};
12244 * @class Roo.bootstrap.Calendar
12245 * @extends Roo.bootstrap.Component
12246 * Bootstrap Calendar class
12247 * @cfg {Boolean} loadMask (true|false) default false
12248 * @cfg {Object} header generate the user specific header of the calendar, default false
12251 * Create a new Container
12252 * @param {Object} config The config object
12257 Roo.bootstrap.Calendar = function(config){
12258 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12262 * Fires when a date is selected
12263 * @param {DatePicker} this
12264 * @param {Date} date The selected date
12268 * @event monthchange
12269 * Fires when the displayed month changes
12270 * @param {DatePicker} this
12271 * @param {Date} date The selected month
12273 'monthchange': true,
12275 * @event evententer
12276 * Fires when mouse over an event
12277 * @param {Calendar} this
12278 * @param {event} Event
12280 'evententer': true,
12282 * @event eventleave
12283 * Fires when the mouse leaves an
12284 * @param {Calendar} this
12287 'eventleave': true,
12289 * @event eventclick
12290 * Fires when the mouse click an
12291 * @param {Calendar} this
12300 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12303 * @cfg {Number} startDay
12304 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12312 getAutoCreate : function(){
12315 var fc_button = function(name, corner, style, content ) {
12316 return Roo.apply({},{
12318 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12320 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12323 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12334 style : 'width:100%',
12341 cls : 'fc-header-left',
12343 fc_button('prev', 'left', 'arrow', '‹' ),
12344 fc_button('next', 'right', 'arrow', '›' ),
12345 { tag: 'span', cls: 'fc-header-space' },
12346 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12354 cls : 'fc-header-center',
12358 cls: 'fc-header-title',
12361 html : 'month / year'
12369 cls : 'fc-header-right',
12371 /* fc_button('month', 'left', '', 'month' ),
12372 fc_button('week', '', '', 'week' ),
12373 fc_button('day', 'right', '', 'day' )
12385 header = this.header;
12388 var cal_heads = function() {
12390 // fixme - handle this.
12392 for (var i =0; i < Date.dayNames.length; i++) {
12393 var d = Date.dayNames[i];
12396 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12397 html : d.substring(0,3)
12401 ret[0].cls += ' fc-first';
12402 ret[6].cls += ' fc-last';
12405 var cal_cell = function(n) {
12408 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12413 cls: 'fc-day-number',
12417 cls: 'fc-day-content',
12421 style: 'position: relative;' // height: 17px;
12433 var cal_rows = function() {
12436 for (var r = 0; r < 6; r++) {
12443 for (var i =0; i < Date.dayNames.length; i++) {
12444 var d = Date.dayNames[i];
12445 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12448 row.cn[0].cls+=' fc-first';
12449 row.cn[0].cn[0].style = 'min-height:90px';
12450 row.cn[6].cls+=' fc-last';
12454 ret[0].cls += ' fc-first';
12455 ret[4].cls += ' fc-prev-last';
12456 ret[5].cls += ' fc-last';
12463 cls: 'fc-border-separate',
12464 style : 'width:100%',
12472 cls : 'fc-first fc-last',
12490 cls : 'fc-content',
12491 style : "position: relative;",
12494 cls : 'fc-view fc-view-month fc-grid',
12495 style : 'position: relative',
12496 unselectable : 'on',
12499 cls : 'fc-event-container',
12500 style : 'position:absolute;z-index:8;top:0;left:0;'
12518 initEvents : function()
12521 throw "can not find store for calendar";
12527 style: "text-align:center",
12531 style: "background-color:white;width:50%;margin:250 auto",
12535 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12546 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12548 var size = this.el.select('.fc-content', true).first().getSize();
12549 this.maskEl.setSize(size.width, size.height);
12550 this.maskEl.enableDisplayMode("block");
12551 if(!this.loadMask){
12552 this.maskEl.hide();
12555 this.store = Roo.factory(this.store, Roo.data);
12556 this.store.on('load', this.onLoad, this);
12557 this.store.on('beforeload', this.onBeforeLoad, this);
12561 this.cells = this.el.select('.fc-day',true);
12562 //Roo.log(this.cells);
12563 this.textNodes = this.el.query('.fc-day-number');
12564 this.cells.addClassOnOver('fc-state-hover');
12566 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12567 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12568 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12569 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12571 this.on('monthchange', this.onMonthChange, this);
12573 this.update(new Date().clearTime());
12576 resize : function() {
12577 var sz = this.el.getSize();
12579 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
12580 this.el.select('.fc-day-content div',true).setHeight(34);
12585 showPrevMonth : function(e){
12586 this.update(this.activeDate.add("mo", -1));
12588 showToday : function(e){
12589 this.update(new Date().clearTime());
12592 showNextMonth : function(e){
12593 this.update(this.activeDate.add("mo", 1));
12597 showPrevYear : function(){
12598 this.update(this.activeDate.add("y", -1));
12602 showNextYear : function(){
12603 this.update(this.activeDate.add("y", 1));
12608 update : function(date)
12610 var vd = this.activeDate;
12611 this.activeDate = date;
12612 // if(vd && this.el){
12613 // var t = date.getTime();
12614 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
12615 // Roo.log('using add remove');
12617 // this.fireEvent('monthchange', this, date);
12619 // this.cells.removeClass("fc-state-highlight");
12620 // this.cells.each(function(c){
12621 // if(c.dateValue == t){
12622 // c.addClass("fc-state-highlight");
12623 // setTimeout(function(){
12624 // try{c.dom.firstChild.focus();}catch(e){}
12634 var days = date.getDaysInMonth();
12636 var firstOfMonth = date.getFirstDateOfMonth();
12637 var startingPos = firstOfMonth.getDay()-this.startDay;
12639 if(startingPos < this.startDay){
12643 var pm = date.add(Date.MONTH, -1);
12644 var prevStart = pm.getDaysInMonth()-startingPos;
12646 this.cells = this.el.select('.fc-day',true);
12647 this.textNodes = this.el.query('.fc-day-number');
12648 this.cells.addClassOnOver('fc-state-hover');
12650 var cells = this.cells.elements;
12651 var textEls = this.textNodes;
12653 Roo.each(cells, function(cell){
12654 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
12657 days += startingPos;
12659 // convert everything to numbers so it's fast
12660 var day = 86400000;
12661 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
12664 //Roo.log(prevStart);
12666 var today = new Date().clearTime().getTime();
12667 var sel = date.clearTime().getTime();
12668 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
12669 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
12670 var ddMatch = this.disabledDatesRE;
12671 var ddText = this.disabledDatesText;
12672 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
12673 var ddaysText = this.disabledDaysText;
12674 var format = this.format;
12676 var setCellClass = function(cal, cell){
12680 //Roo.log('set Cell Class');
12682 var t = d.getTime();
12686 cell.dateValue = t;
12688 cell.className += " fc-today";
12689 cell.className += " fc-state-highlight";
12690 cell.title = cal.todayText;
12693 // disable highlight in other month..
12694 //cell.className += " fc-state-highlight";
12699 cell.className = " fc-state-disabled";
12700 cell.title = cal.minText;
12704 cell.className = " fc-state-disabled";
12705 cell.title = cal.maxText;
12709 if(ddays.indexOf(d.getDay()) != -1){
12710 cell.title = ddaysText;
12711 cell.className = " fc-state-disabled";
12714 if(ddMatch && format){
12715 var fvalue = d.dateFormat(format);
12716 if(ddMatch.test(fvalue)){
12717 cell.title = ddText.replace("%0", fvalue);
12718 cell.className = " fc-state-disabled";
12722 if (!cell.initialClassName) {
12723 cell.initialClassName = cell.dom.className;
12726 cell.dom.className = cell.initialClassName + ' ' + cell.className;
12731 for(; i < startingPos; i++) {
12732 textEls[i].innerHTML = (++prevStart);
12733 d.setDate(d.getDate()+1);
12735 cells[i].className = "fc-past fc-other-month";
12736 setCellClass(this, cells[i]);
12741 for(; i < days; i++){
12742 intDay = i - startingPos + 1;
12743 textEls[i].innerHTML = (intDay);
12744 d.setDate(d.getDate()+1);
12746 cells[i].className = ''; // "x-date-active";
12747 setCellClass(this, cells[i]);
12751 for(; i < 42; i++) {
12752 textEls[i].innerHTML = (++extraDays);
12753 d.setDate(d.getDate()+1);
12755 cells[i].className = "fc-future fc-other-month";
12756 setCellClass(this, cells[i]);
12759 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
12761 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
12763 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
12764 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
12766 if(totalRows != 6){
12767 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
12768 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
12771 this.fireEvent('monthchange', this, date);
12775 if(!this.internalRender){
12776 var main = this.el.dom.firstChild;
12777 var w = main.offsetWidth;
12778 this.el.setWidth(w + this.el.getBorderWidth("lr"));
12779 Roo.fly(main).setWidth(w);
12780 this.internalRender = true;
12781 // opera does not respect the auto grow header center column
12782 // then, after it gets a width opera refuses to recalculate
12783 // without a second pass
12784 if(Roo.isOpera && !this.secondPass){
12785 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
12786 this.secondPass = true;
12787 this.update.defer(10, this, [date]);
12794 findCell : function(dt) {
12795 dt = dt.clearTime().getTime();
12797 this.cells.each(function(c){
12798 //Roo.log("check " +c.dateValue + '?=' + dt);
12799 if(c.dateValue == dt){
12809 findCells : function(ev) {
12810 var s = ev.start.clone().clearTime().getTime();
12812 var e= ev.end.clone().clearTime().getTime();
12815 this.cells.each(function(c){
12816 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
12818 if(c.dateValue > e){
12821 if(c.dateValue < s){
12830 // findBestRow: function(cells)
12834 // for (var i =0 ; i < cells.length;i++) {
12835 // ret = Math.max(cells[i].rows || 0,ret);
12842 addItem : function(ev)
12844 // look for vertical location slot in
12845 var cells = this.findCells(ev);
12847 // ev.row = this.findBestRow(cells);
12849 // work out the location.
12853 for(var i =0; i < cells.length; i++) {
12855 cells[i].row = cells[0].row;
12858 cells[i].row = cells[i].row + 1;
12868 if (crow.start.getY() == cells[i].getY()) {
12870 crow.end = cells[i];
12887 cells[0].events.push(ev);
12889 this.calevents.push(ev);
12892 clearEvents: function() {
12894 if(!this.calevents){
12898 Roo.each(this.cells.elements, function(c){
12904 Roo.each(this.calevents, function(e) {
12905 Roo.each(e.els, function(el) {
12906 el.un('mouseenter' ,this.onEventEnter, this);
12907 el.un('mouseleave' ,this.onEventLeave, this);
12912 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
12918 renderEvents: function()
12922 this.cells.each(function(c) {
12931 if(c.row != c.events.length){
12932 r = 4 - (4 - (c.row - c.events.length));
12935 c.events = ev.slice(0, r);
12936 c.more = ev.slice(r);
12938 if(c.more.length && c.more.length == 1){
12939 c.events.push(c.more.pop());
12942 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
12946 this.cells.each(function(c) {
12948 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
12951 for (var e = 0; e < c.events.length; e++){
12952 var ev = c.events[e];
12953 var rows = ev.rows;
12955 for(var i = 0; i < rows.length; i++) {
12957 // how many rows should it span..
12960 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
12961 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
12963 unselectable : "on",
12966 cls: 'fc-event-inner',
12970 // cls: 'fc-event-time',
12971 // html : cells.length > 1 ? '' : ev.time
12975 cls: 'fc-event-title',
12976 html : String.format('{0}', ev.title)
12983 cls: 'ui-resizable-handle ui-resizable-e',
12984 html : '  '
12991 cfg.cls += ' fc-event-start';
12993 if ((i+1) == rows.length) {
12994 cfg.cls += ' fc-event-end';
12997 var ctr = _this.el.select('.fc-event-container',true).first();
12998 var cg = ctr.createChild(cfg);
13000 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13001 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13003 var r = (c.more.length) ? 1 : 0;
13004 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13005 cg.setWidth(ebox.right - sbox.x -2);
13007 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13008 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13009 cg.on('click', _this.onEventClick, _this, ev);
13020 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13021 style : 'position: absolute',
13022 unselectable : "on",
13025 cls: 'fc-event-inner',
13029 cls: 'fc-event-title',
13037 cls: 'ui-resizable-handle ui-resizable-e',
13038 html : '  '
13044 var ctr = _this.el.select('.fc-event-container',true).first();
13045 var cg = ctr.createChild(cfg);
13047 var sbox = c.select('.fc-day-content',true).first().getBox();
13048 var ebox = c.select('.fc-day-content',true).first().getBox();
13050 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13051 cg.setWidth(ebox.right - sbox.x -2);
13053 cg.on('click', _this.onMoreEventClick, _this, c.more);
13063 onEventEnter: function (e, el,event,d) {
13064 this.fireEvent('evententer', this, el, event);
13067 onEventLeave: function (e, el,event,d) {
13068 this.fireEvent('eventleave', this, el, event);
13071 onEventClick: function (e, el,event,d) {
13072 this.fireEvent('eventclick', this, el, event);
13075 onMonthChange: function () {
13079 onMoreEventClick: function(e, el, more)
13083 this.calpopover.placement = 'right';
13084 this.calpopover.setTitle('More');
13086 this.calpopover.setContent('');
13088 var ctr = this.calpopover.el.select('.popover-content', true).first();
13090 Roo.each(more, function(m){
13092 cls : 'fc-event-hori fc-event-draggable',
13095 var cg = ctr.createChild(cfg);
13097 cg.on('click', _this.onEventClick, _this, m);
13100 this.calpopover.show(el);
13105 onLoad: function ()
13107 this.calevents = [];
13110 if(this.store.getCount() > 0){
13111 this.store.data.each(function(d){
13114 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13115 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13116 time : d.data.start_time,
13117 title : d.data.title,
13118 description : d.data.description,
13119 venue : d.data.venue
13124 this.renderEvents();
13126 if(this.calevents.length && this.loadMask){
13127 this.maskEl.hide();
13131 onBeforeLoad: function()
13133 this.clearEvents();
13135 this.maskEl.show();
13149 * @class Roo.bootstrap.Popover
13150 * @extends Roo.bootstrap.Component
13151 * Bootstrap Popover class
13152 * @cfg {String} html contents of the popover (or false to use children..)
13153 * @cfg {String} title of popover (or false to hide)
13154 * @cfg {String} placement how it is placed
13155 * @cfg {String} trigger click || hover (or false to trigger manually)
13156 * @cfg {String} over what (parent or false to trigger manually.)
13159 * Create a new Popover
13160 * @param {Object} config The config object
13163 Roo.bootstrap.Popover = function(config){
13164 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13167 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13169 title: 'Fill in a title',
13172 placement : 'right',
13173 trigger : 'hover', // hover
13177 can_build_overlaid : false,
13179 getChildContainer : function()
13181 return this.el.select('.popover-content',true).first();
13184 getAutoCreate : function(){
13185 Roo.log('make popover?');
13187 cls : 'popover roo-dynamic',
13188 style: 'display:block',
13194 cls : 'popover-inner',
13198 cls: 'popover-title',
13202 cls : 'popover-content',
13213 setTitle: function(str)
13215 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13217 setContent: function(str)
13219 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13221 // as it get's added to the bottom of the page.
13222 onRender : function(ct, position)
13224 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13226 var cfg = Roo.apply({}, this.getAutoCreate());
13230 cfg.cls += ' ' + this.cls;
13233 cfg.style = this.style;
13235 Roo.log("adding to ")
13236 this.el = Roo.get(document.body).createChild(cfg, position);
13242 initEvents : function()
13244 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13245 this.el.enableDisplayMode('block');
13247 if (this.over === false) {
13250 if (this.triggers === false) {
13253 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13254 var triggers = this.trigger ? this.trigger.split(' ') : [];
13255 Roo.each(triggers, function(trigger) {
13257 if (trigger == 'click') {
13258 on_el.on('click', this.toggle, this);
13259 } else if (trigger != 'manual') {
13260 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13261 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13263 on_el.on(eventIn ,this.enter, this);
13264 on_el.on(eventOut, this.leave, this);
13275 toggle : function () {
13276 this.hoverState == 'in' ? this.leave() : this.enter();
13279 enter : function () {
13282 clearTimeout(this.timeout);
13284 this.hoverState = 'in'
13286 if (!this.delay || !this.delay.show) {
13291 this.timeout = setTimeout(function () {
13292 if (_t.hoverState == 'in') {
13295 }, this.delay.show)
13297 leave : function() {
13298 clearTimeout(this.timeout);
13300 this.hoverState = 'out'
13302 if (!this.delay || !this.delay.hide) {
13307 this.timeout = setTimeout(function () {
13308 if (_t.hoverState == 'out') {
13311 }, this.delay.hide)
13314 show : function (on_el)
13317 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13320 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13321 if (this.html !== false) {
13322 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13324 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13325 if (!this.title.length) {
13326 this.el.select('.popover-title',true).hide();
13329 var placement = typeof this.placement == 'function' ?
13330 this.placement.call(this, this.el, on_el) :
13333 var autoToken = /\s?auto?\s?/i;
13334 var autoPlace = autoToken.test(placement);
13336 placement = placement.replace(autoToken, '') || 'top';
13340 //this.el.setXY([0,0]);
13342 this.el.dom.style.display='block';
13343 this.el.addClass(placement);
13345 //this.el.appendTo(on_el);
13347 var p = this.getPosition();
13348 var box = this.el.getBox();
13353 var align = Roo.bootstrap.Popover.alignment[placement]
13354 this.el.alignTo(on_el, align[0],align[1]);
13355 //var arrow = this.el.select('.arrow',true).first();
13356 //arrow.set(align[2],
13358 this.el.addClass('in');
13359 this.hoverState = null;
13361 if (this.el.hasClass('fade')) {
13368 this.el.setXY([0,0]);
13369 this.el.removeClass('in');
13376 Roo.bootstrap.Popover.alignment = {
13377 'left' : ['r-l', [-10,0], 'right'],
13378 'right' : ['l-r', [10,0], 'left'],
13379 'bottom' : ['t-b', [0,10], 'top'],
13380 'top' : [ 'b-t', [0,-10], 'bottom']
13391 * @class Roo.bootstrap.Progress
13392 * @extends Roo.bootstrap.Component
13393 * Bootstrap Progress class
13394 * @cfg {Boolean} striped striped of the progress bar
13395 * @cfg {Boolean} active animated of the progress bar
13399 * Create a new Progress
13400 * @param {Object} config The config object
13403 Roo.bootstrap.Progress = function(config){
13404 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13407 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13412 getAutoCreate : function(){
13420 cfg.cls += ' progress-striped';
13424 cfg.cls += ' active';
13443 * @class Roo.bootstrap.ProgressBar
13444 * @extends Roo.bootstrap.Component
13445 * Bootstrap ProgressBar class
13446 * @cfg {Number} aria_valuenow aria-value now
13447 * @cfg {Number} aria_valuemin aria-value min
13448 * @cfg {Number} aria_valuemax aria-value max
13449 * @cfg {String} label label for the progress bar
13450 * @cfg {String} panel (success | info | warning | danger )
13451 * @cfg {String} role role of the progress bar
13452 * @cfg {String} sr_only text
13456 * Create a new ProgressBar
13457 * @param {Object} config The config object
13460 Roo.bootstrap.ProgressBar = function(config){
13461 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13464 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13468 aria_valuemax : 100,
13474 getAutoCreate : function()
13479 cls: 'progress-bar',
13480 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13492 cfg.role = this.role;
13495 if(this.aria_valuenow){
13496 cfg['aria-valuenow'] = this.aria_valuenow;
13499 if(this.aria_valuemin){
13500 cfg['aria-valuemin'] = this.aria_valuemin;
13503 if(this.aria_valuemax){
13504 cfg['aria-valuemax'] = this.aria_valuemax;
13507 if(this.label && !this.sr_only){
13508 cfg.html = this.label;
13512 cfg.cls += ' progress-bar-' + this.panel;
13518 update : function(aria_valuenow)
13520 this.aria_valuenow = aria_valuenow;
13522 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13537 * @class Roo.bootstrap.TabPanel
13538 * @extends Roo.bootstrap.Component
13539 * Bootstrap TabPanel class
13540 * @cfg {Boolean} active panel active
13541 * @cfg {String} html panel content
13542 * @cfg {String} tabId tab relate id
13543 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
13547 * Create a new TabPanel
13548 * @param {Object} config The config object
13551 Roo.bootstrap.TabPanel = function(config){
13552 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
13556 * Fires when the active status changes
13557 * @param {Roo.bootstrap.TabPanel} this
13558 * @param {Boolean} state the new state
13565 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
13572 getAutoCreate : function(){
13576 html: this.html || ''
13580 cfg.cls += ' active';
13584 cfg.tabId = this.tabId;
13589 onRender : function(ct, position)
13591 // Roo.log("Call onRender: " + this.xtype);
13593 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
13595 if (this.navId && this.tabId) {
13596 var item = Roo.bootstrap.NavGroup.get(this.navId).getNavItem(this.tabId);
13598 Roo.log("could not find navID:" + this.navId + ", tabId: " + this.tabId);
13600 item.on('changed', function(item, state) {
13601 this.setActive(state);
13607 setActive: function(state)
13609 Roo.log("panel - set active " + this.tabId + "=" + state);
13611 this.active = state;
13613 this.el.removeClass('active');
13615 } else if (!this.el.hasClass('active')) {
13616 this.el.addClass('active');
13618 this.fireEvent('changed', this, state);
13635 * @class Roo.bootstrap.DateField
13636 * @extends Roo.bootstrap.Input
13637 * Bootstrap DateField class
13638 * @cfg {Number} weekStart default 0
13639 * @cfg {Number} weekStart default 0
13640 * @cfg {Number} viewMode default empty, (months|years)
13641 * @cfg {Number} minViewMode default empty, (months|years)
13642 * @cfg {Number} startDate default -Infinity
13643 * @cfg {Number} endDate default Infinity
13644 * @cfg {Boolean} todayHighlight default false
13645 * @cfg {Boolean} todayBtn default false
13646 * @cfg {Boolean} calendarWeeks default false
13647 * @cfg {Object} daysOfWeekDisabled default empty
13649 * @cfg {Boolean} keyboardNavigation default true
13650 * @cfg {String} language default en
13653 * Create a new DateField
13654 * @param {Object} config The config object
13657 Roo.bootstrap.DateField = function(config){
13658 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
13662 * Fires when this field show.
13663 * @param {Roo.bootstrap.DateField} this
13664 * @param {Mixed} date The date value
13669 * Fires when this field hide.
13670 * @param {Roo.bootstrap.DateField} this
13671 * @param {Mixed} date The date value
13676 * Fires when select a date.
13677 * @param {Roo.bootstrap.DateField} this
13678 * @param {Mixed} date The date value
13684 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
13687 * @cfg {String} format
13688 * The default date format string which can be overriden for localization support. The format must be
13689 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
13693 * @cfg {String} altFormats
13694 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
13695 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
13697 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
13705 todayHighlight : false,
13711 keyboardNavigation: true,
13713 calendarWeeks: false,
13715 startDate: -Infinity,
13719 daysOfWeekDisabled: [],
13723 UTCDate: function()
13725 return new Date(Date.UTC.apply(Date, arguments));
13728 UTCToday: function()
13730 var today = new Date();
13731 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
13734 getDate: function() {
13735 var d = this.getUTCDate();
13736 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
13739 getUTCDate: function() {
13743 setDate: function(d) {
13744 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
13747 setUTCDate: function(d) {
13749 this.setValue(this.formatDate(this.date));
13752 onRender: function(ct, position)
13755 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
13757 this.language = this.language || 'en';
13758 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
13759 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
13761 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
13762 this.format = this.format || 'm/d/y';
13763 this.isInline = false;
13764 this.isInput = true;
13765 this.component = this.el.select('.add-on', true).first() || false;
13766 this.component = (this.component && this.component.length === 0) ? false : this.component;
13767 this.hasInput = this.component && this.inputEL().length;
13769 if (typeof(this.minViewMode === 'string')) {
13770 switch (this.minViewMode) {
13772 this.minViewMode = 1;
13775 this.minViewMode = 2;
13778 this.minViewMode = 0;
13783 if (typeof(this.viewMode === 'string')) {
13784 switch (this.viewMode) {
13797 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
13799 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13801 this.picker().on('mousedown', this.onMousedown, this);
13802 this.picker().on('click', this.onClick, this);
13804 this.picker().addClass('datepicker-dropdown');
13806 this.startViewMode = this.viewMode;
13809 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
13810 if(!this.calendarWeeks){
13815 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
13816 v.attr('colspan', function(i, val){
13817 return parseInt(val) + 1;
13822 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
13824 this.setStartDate(this.startDate);
13825 this.setEndDate(this.endDate);
13827 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
13834 if(this.isInline) {
13839 picker : function()
13841 return this.el.select('.datepicker', true).first();
13844 fillDow: function()
13846 var dowCnt = this.weekStart;
13855 if(this.calendarWeeks){
13863 while (dowCnt < this.weekStart + 7) {
13867 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
13871 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
13874 fillMonths: function()
13877 var months = this.picker().select('>.datepicker-months td', true).first();
13879 months.dom.innerHTML = '';
13885 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
13888 months.createChild(month);
13896 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
13898 if (this.date < this.startDate) {
13899 this.viewDate = new Date(this.startDate);
13900 } else if (this.date > this.endDate) {
13901 this.viewDate = new Date(this.endDate);
13903 this.viewDate = new Date(this.date);
13911 var d = new Date(this.viewDate),
13912 year = d.getUTCFullYear(),
13913 month = d.getUTCMonth(),
13914 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
13915 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
13916 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
13917 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
13918 currentDate = this.date && this.date.valueOf(),
13919 today = this.UTCToday();
13921 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
13923 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
13925 // this.picker.select('>tfoot th.today').
13926 // .text(dates[this.language].today)
13927 // .toggle(this.todayBtn !== false);
13929 this.updateNavArrows();
13932 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
13934 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
13936 prevMonth.setUTCDate(day);
13938 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
13940 var nextMonth = new Date(prevMonth);
13942 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
13944 nextMonth = nextMonth.valueOf();
13946 var fillMonths = false;
13948 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
13950 while(prevMonth.valueOf() < nextMonth) {
13953 if (prevMonth.getUTCDay() === this.weekStart) {
13955 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
13963 if(this.calendarWeeks){
13964 // ISO 8601: First week contains first thursday.
13965 // ISO also states week starts on Monday, but we can be more abstract here.
13967 // Start of current week: based on weekstart/current date
13968 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
13969 // Thursday of this week
13970 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
13971 // First Thursday of year, year from thursday
13972 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
13973 // Calendar week: ms between thursdays, div ms per day, div 7 days
13974 calWeek = (th - yth) / 864e5 / 7 + 1;
13976 fillMonths.cn.push({
13984 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
13986 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
13989 if (this.todayHighlight &&
13990 prevMonth.getUTCFullYear() == today.getFullYear() &&
13991 prevMonth.getUTCMonth() == today.getMonth() &&
13992 prevMonth.getUTCDate() == today.getDate()) {
13993 clsName += ' today';
13996 if (currentDate && prevMonth.valueOf() === currentDate) {
13997 clsName += ' active';
14000 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14001 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14002 clsName += ' disabled';
14005 fillMonths.cn.push({
14007 cls: 'day ' + clsName,
14008 html: prevMonth.getDate()
14011 prevMonth.setDate(prevMonth.getDate()+1);
14014 var currentYear = this.date && this.date.getUTCFullYear();
14015 var currentMonth = this.date && this.date.getUTCMonth();
14017 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14019 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14020 v.removeClass('active');
14022 if(currentYear === year && k === currentMonth){
14023 v.addClass('active');
14026 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14027 v.addClass('disabled');
14033 year = parseInt(year/10, 10) * 10;
14035 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14037 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14040 for (var i = -1; i < 11; i++) {
14041 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14043 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14051 showMode: function(dir)
14054 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14056 Roo.each(this.picker().select('>div',true).elements, function(v){
14057 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14060 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14065 if(this.isInline) return;
14067 this.picker().removeClass(['bottom', 'top']);
14069 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14071 * place to the top of element!
14075 this.picker().addClass('top');
14076 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14081 this.picker().addClass('bottom');
14083 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14086 parseDate : function(value)
14088 if(!value || value instanceof Date){
14091 var v = Date.parseDate(value, this.format);
14092 if (!v && this.useIso) {
14093 v = Date.parseDate(value, 'Y-m-d');
14095 if(!v && this.altFormats){
14096 if(!this.altFormatsArray){
14097 this.altFormatsArray = this.altFormats.split("|");
14099 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14100 v = Date.parseDate(value, this.altFormatsArray[i]);
14106 formatDate : function(date, fmt)
14108 return (!date || !(date instanceof Date)) ?
14109 date : date.dateFormat(fmt || this.format);
14112 onFocus : function()
14114 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14118 onBlur : function()
14120 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14122 var d = this.inputEl().getValue();
14133 this.picker().show();
14137 this.fireEvent('show', this, this.date);
14142 if(this.isInline) return;
14143 this.picker().hide();
14144 this.viewMode = this.startViewMode;
14147 this.fireEvent('hide', this, this.date);
14151 onMousedown: function(e)
14153 e.stopPropagation();
14154 e.preventDefault();
14159 Roo.bootstrap.DateField.superclass.keyup.call(this);
14163 setValue: function(v)
14165 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14167 var d = new Date(v);
14169 if(isNaN(d.getTime())){
14173 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14177 this.fireEvent('select', this, this.date);
14181 getValue: function()
14183 return this.formatDate(this.date);
14186 fireKey: function(e)
14188 if (!this.picker().isVisible()){
14189 if (e.keyCode == 27) // allow escape to hide and re-show picker
14193 var dateChanged = false,
14195 newDate, newViewDate;
14200 e.preventDefault();
14204 if (!this.keyboardNavigation) break;
14205 dir = e.keyCode == 37 ? -1 : 1;
14208 newDate = this.moveYear(this.date, dir);
14209 newViewDate = this.moveYear(this.viewDate, dir);
14210 } else if (e.shiftKey){
14211 newDate = this.moveMonth(this.date, dir);
14212 newViewDate = this.moveMonth(this.viewDate, dir);
14214 newDate = new Date(this.date);
14215 newDate.setUTCDate(this.date.getUTCDate() + dir);
14216 newViewDate = new Date(this.viewDate);
14217 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14219 if (this.dateWithinRange(newDate)){
14220 this.date = newDate;
14221 this.viewDate = newViewDate;
14222 this.setValue(this.formatDate(this.date));
14224 e.preventDefault();
14225 dateChanged = true;
14230 if (!this.keyboardNavigation) break;
14231 dir = e.keyCode == 38 ? -1 : 1;
14233 newDate = this.moveYear(this.date, dir);
14234 newViewDate = this.moveYear(this.viewDate, dir);
14235 } else if (e.shiftKey){
14236 newDate = this.moveMonth(this.date, dir);
14237 newViewDate = this.moveMonth(this.viewDate, dir);
14239 newDate = new Date(this.date);
14240 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14241 newViewDate = new Date(this.viewDate);
14242 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14244 if (this.dateWithinRange(newDate)){
14245 this.date = newDate;
14246 this.viewDate = newViewDate;
14247 this.setValue(this.formatDate(this.date));
14249 e.preventDefault();
14250 dateChanged = true;
14254 this.setValue(this.formatDate(this.date));
14256 e.preventDefault();
14259 this.setValue(this.formatDate(this.date));
14267 onClick: function(e)
14269 e.stopPropagation();
14270 e.preventDefault();
14272 var target = e.getTarget();
14274 if(target.nodeName.toLowerCase() === 'i'){
14275 target = Roo.get(target).dom.parentNode;
14278 var nodeName = target.nodeName;
14279 var className = target.className;
14280 var html = target.innerHTML;
14282 switch(nodeName.toLowerCase()) {
14284 switch(className) {
14290 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14291 switch(this.viewMode){
14293 this.viewDate = this.moveMonth(this.viewDate, dir);
14297 this.viewDate = this.moveYear(this.viewDate, dir);
14303 var date = new Date();
14304 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14306 this.setValue(this.formatDate(this.date));
14313 if (className.indexOf('disabled') === -1) {
14314 this.viewDate.setUTCDate(1);
14315 if (className.indexOf('month') !== -1) {
14316 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14318 var year = parseInt(html, 10) || 0;
14319 this.viewDate.setUTCFullYear(year);
14328 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
14329 var day = parseInt(html, 10) || 1;
14330 var year = this.viewDate.getUTCFullYear(),
14331 month = this.viewDate.getUTCMonth();
14333 if (className.indexOf('old') !== -1) {
14340 } else if (className.indexOf('new') !== -1) {
14348 this.date = this.UTCDate(year, month, day,0,0,0,0);
14349 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
14351 this.setValue(this.formatDate(this.date));
14358 setStartDate: function(startDate)
14360 this.startDate = startDate || -Infinity;
14361 if (this.startDate !== -Infinity) {
14362 this.startDate = this.parseDate(this.startDate);
14365 this.updateNavArrows();
14368 setEndDate: function(endDate)
14370 this.endDate = endDate || Infinity;
14371 if (this.endDate !== Infinity) {
14372 this.endDate = this.parseDate(this.endDate);
14375 this.updateNavArrows();
14378 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
14380 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
14381 if (typeof(this.daysOfWeekDisabled) !== 'object') {
14382 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
14384 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
14385 return parseInt(d, 10);
14388 this.updateNavArrows();
14391 updateNavArrows: function()
14393 var d = new Date(this.viewDate),
14394 year = d.getUTCFullYear(),
14395 month = d.getUTCMonth();
14397 Roo.each(this.picker().select('.prev', true).elements, function(v){
14399 switch (this.viewMode) {
14402 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
14408 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
14415 Roo.each(this.picker().select('.next', true).elements, function(v){
14417 switch (this.viewMode) {
14420 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
14426 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
14434 moveMonth: function(date, dir)
14436 if (!dir) return date;
14437 var new_date = new Date(date.valueOf()),
14438 day = new_date.getUTCDate(),
14439 month = new_date.getUTCMonth(),
14440 mag = Math.abs(dir),
14442 dir = dir > 0 ? 1 : -1;
14445 // If going back one month, make sure month is not current month
14446 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
14448 return new_date.getUTCMonth() == month;
14450 // If going forward one month, make sure month is as expected
14451 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
14453 return new_date.getUTCMonth() != new_month;
14455 new_month = month + dir;
14456 new_date.setUTCMonth(new_month);
14457 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
14458 if (new_month < 0 || new_month > 11)
14459 new_month = (new_month + 12) % 12;
14461 // For magnitudes >1, move one month at a time...
14462 for (var i=0; i<mag; i++)
14463 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
14464 new_date = this.moveMonth(new_date, dir);
14465 // ...then reset the day, keeping it in the new month
14466 new_month = new_date.getUTCMonth();
14467 new_date.setUTCDate(day);
14469 return new_month != new_date.getUTCMonth();
14472 // Common date-resetting loop -- if date is beyond end of month, make it
14475 new_date.setUTCDate(--day);
14476 new_date.setUTCMonth(new_month);
14481 moveYear: function(date, dir)
14483 return this.moveMonth(date, dir*12);
14486 dateWithinRange: function(date)
14488 return date >= this.startDate && date <= this.endDate;
14494 this.picker().remove();
14499 Roo.apply(Roo.bootstrap.DateField, {
14510 html: '<i class="fa fa-arrow-left"/>'
14520 html: '<i class="fa fa-arrow-right"/>'
14562 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
14563 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
14564 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
14565 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
14566 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
14579 navFnc: 'FullYear',
14584 navFnc: 'FullYear',
14589 Roo.apply(Roo.bootstrap.DateField, {
14593 cls: 'datepicker dropdown-menu',
14597 cls: 'datepicker-days',
14601 cls: 'table-condensed',
14603 Roo.bootstrap.DateField.head,
14607 Roo.bootstrap.DateField.footer
14614 cls: 'datepicker-months',
14618 cls: 'table-condensed',
14620 Roo.bootstrap.DateField.head,
14621 Roo.bootstrap.DateField.content,
14622 Roo.bootstrap.DateField.footer
14629 cls: 'datepicker-years',
14633 cls: 'table-condensed',
14635 Roo.bootstrap.DateField.head,
14636 Roo.bootstrap.DateField.content,
14637 Roo.bootstrap.DateField.footer
14656 * @class Roo.bootstrap.TimeField
14657 * @extends Roo.bootstrap.Input
14658 * Bootstrap DateField class
14662 * Create a new TimeField
14663 * @param {Object} config The config object
14666 Roo.bootstrap.TimeField = function(config){
14667 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
14671 * Fires when this field show.
14672 * @param {Roo.bootstrap.DateField} this
14673 * @param {Mixed} date The date value
14678 * Fires when this field hide.
14679 * @param {Roo.bootstrap.DateField} this
14680 * @param {Mixed} date The date value
14685 * Fires when select a date.
14686 * @param {Roo.bootstrap.DateField} this
14687 * @param {Mixed} date The date value
14693 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
14696 * @cfg {String} format
14697 * The default time format string which can be overriden for localization support. The format must be
14698 * valid according to {@link Date#parseDate} (defaults to 'H:i').
14702 onRender: function(ct, position)
14705 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
14707 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
14709 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14711 this.pop = this.picker().select('>.datepicker-time',true).first();
14712 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
14714 this.picker().on('mousedown', this.onMousedown, this);
14715 this.picker().on('click', this.onClick, this);
14717 this.picker().addClass('datepicker-dropdown');
14722 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
14723 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
14724 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
14725 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
14726 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
14727 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
14731 fireKey: function(e){
14732 if (!this.picker().isVisible()){
14733 if (e.keyCode == 27) // allow escape to hide and re-show picker
14738 e.preventDefault();
14746 this.onTogglePeriod();
14749 this.onIncrementMinutes();
14752 this.onDecrementMinutes();
14761 onClick: function(e) {
14762 e.stopPropagation();
14763 e.preventDefault();
14766 picker : function()
14768 return this.el.select('.datepicker', true).first();
14771 fillTime: function()
14773 var time = this.pop.select('tbody', true).first();
14775 time.dom.innerHTML = '';
14790 cls: 'hours-up glyphicon glyphicon-chevron-up'
14810 cls: 'minutes-up glyphicon glyphicon-chevron-up'
14831 cls: 'timepicker-hour',
14846 cls: 'timepicker-minute',
14861 cls: 'btn btn-primary period',
14883 cls: 'hours-down glyphicon glyphicon-chevron-down'
14903 cls: 'minutes-down glyphicon glyphicon-chevron-down'
14921 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
14928 var hours = this.time.getHours();
14929 var minutes = this.time.getMinutes();
14942 hours = hours - 12;
14946 hours = '0' + hours;
14950 minutes = '0' + minutes;
14953 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
14954 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
14955 this.pop.select('button', true).first().dom.innerHTML = period;
14961 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
14963 var cls = ['bottom'];
14965 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
14972 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
14977 this.picker().addClass(cls.join('-'));
14981 Roo.each(cls, function(c){
14983 _this.picker().setTop(_this.inputEl().getHeight());
14987 _this.picker().setTop(0 - _this.picker().getHeight());
14992 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
14996 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15003 onFocus : function()
15005 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15009 onBlur : function()
15011 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15017 this.picker().show();
15022 this.fireEvent('show', this, this.date);
15027 this.picker().hide();
15030 this.fireEvent('hide', this, this.date);
15033 setTime : function()
15036 this.setValue(this.time.format(this.format));
15038 this.fireEvent('select', this, this.date);
15043 onMousedown: function(e){
15044 e.stopPropagation();
15045 e.preventDefault();
15048 onIncrementHours: function()
15050 Roo.log('onIncrementHours');
15051 this.time = this.time.add(Date.HOUR, 1);
15056 onDecrementHours: function()
15058 Roo.log('onDecrementHours');
15059 this.time = this.time.add(Date.HOUR, -1);
15063 onIncrementMinutes: function()
15065 Roo.log('onIncrementMinutes');
15066 this.time = this.time.add(Date.MINUTE, 1);
15070 onDecrementMinutes: function()
15072 Roo.log('onDecrementMinutes');
15073 this.time = this.time.add(Date.MINUTE, -1);
15077 onTogglePeriod: function()
15079 Roo.log('onTogglePeriod');
15080 this.time = this.time.add(Date.HOUR, 12);
15087 Roo.apply(Roo.bootstrap.TimeField, {
15117 cls: 'btn btn-info ok',
15129 Roo.apply(Roo.bootstrap.TimeField, {
15133 cls: 'datepicker dropdown-menu',
15137 cls: 'datepicker-time',
15141 cls: 'table-condensed',
15143 Roo.bootstrap.TimeField.content,
15144 Roo.bootstrap.TimeField.footer
15163 * @class Roo.bootstrap.CheckBox
15164 * @extends Roo.bootstrap.Input
15165 * Bootstrap CheckBox class
15167 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15168 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15169 * @cfg {String} boxLabel The text that appears beside the checkbox
15170 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15171 * @cfg {Boolean} checked initnal the element
15175 * Create a new CheckBox
15176 * @param {Object} config The config object
15179 Roo.bootstrap.CheckBox = function(config){
15180 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15185 * Fires when the element is checked or unchecked.
15186 * @param {Roo.bootstrap.CheckBox} this This input
15187 * @param {Boolean} checked The new checked value
15193 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15195 inputType: 'checkbox',
15202 getAutoCreate : function()
15204 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15210 cfg.cls = 'form-group checkbox' //input-group
15218 type : this.inputType,
15219 value : (!this.checked) ? this.valueOff : this.inputValue,
15220 cls : 'roo-checkbox', //'form-box',
15221 placeholder : this.placeholder || ''
15225 if (this.weight) { // Validity check?
15226 cfg.cls += " checkbox-" + this.weight;
15229 if (this.disabled) {
15230 input.disabled=true;
15234 input.checked = this.checked;
15238 input.name = this.name;
15242 input.cls += ' input-' + this.size;
15246 ['xs','sm','md','lg'].map(function(size){
15247 if (settings[size]) {
15248 cfg.cls += ' col-' + size + '-' + settings[size];
15254 var inputblock = input;
15259 if (this.before || this.after) {
15262 cls : 'input-group',
15266 inputblock.cn.push({
15268 cls : 'input-group-addon',
15272 inputblock.cn.push(input);
15274 inputblock.cn.push({
15276 cls : 'input-group-addon',
15283 if (align ==='left' && this.fieldLabel.length) {
15284 Roo.log("left and has label");
15290 cls : 'control-label col-md-' + this.labelWidth,
15291 html : this.fieldLabel
15295 cls : "col-md-" + (12 - this.labelWidth),
15302 } else if ( this.fieldLabel.length) {
15307 tag: this.boxLabel ? 'span' : 'label',
15309 cls: 'control-label box-input-label',
15310 //cls : 'input-group-addon',
15311 html : this.fieldLabel
15321 Roo.log(" no label && no align");
15322 cfg.cn = [ inputblock ] ;
15331 html: this.boxLabel
15343 * return the real input element.
15345 inputEl: function ()
15347 return this.el.select('input.roo-checkbox',true).first();
15352 return this.el.select('label.control-label',true).first();
15355 initEvents : function()
15357 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
15359 this.inputEl().on('click', this.onClick, this);
15363 onClick : function()
15365 this.setChecked(!this.checked);
15368 setChecked : function(state,suppressEvent)
15370 this.checked = state;
15372 this.inputEl().dom.checked = state;
15374 if(suppressEvent !== true){
15375 this.fireEvent('check', this, state);
15378 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15382 setValue : function(v,suppressEvent)
15384 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
15398 * @class Roo.bootstrap.Radio
15399 * @extends Roo.bootstrap.CheckBox
15400 * Bootstrap Radio class
15403 * Create a new Radio
15404 * @param {Object} config The config object
15407 Roo.bootstrap.Radio = function(config){
15408 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
15412 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
15414 inputType: 'radio',
15418 getAutoCreate : function()
15420 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15426 cfg.cls = 'form-group radio' //input-group
15431 type : this.inputType,
15432 value : (!this.checked) ? this.valueOff : this.inputValue,
15434 placeholder : this.placeholder || ''
15437 if (this.weight) { // Validity check?
15438 cfg.cls += " radio-" + this.weight;
15440 if (this.disabled) {
15441 input.disabled=true;
15445 input.checked = this.checked;
15449 input.name = this.name;
15453 input.cls += ' input-' + this.size;
15457 ['xs','sm','md','lg'].map(function(size){
15458 if (settings[size]) {
15459 cfg.cls += ' col-' + size + '-' + settings[size];
15463 var inputblock = input;
15465 if (this.before || this.after) {
15468 cls : 'input-group',
15472 inputblock.cn.push({
15474 cls : 'input-group-addon',
15478 inputblock.cn.push(input);
15480 inputblock.cn.push({
15482 cls : 'input-group-addon',
15489 if (align ==='left' && this.fieldLabel.length) {
15490 Roo.log("left and has label");
15496 cls : 'control-label col-md-' + this.labelWidth,
15497 html : this.fieldLabel
15501 cls : "col-md-" + (12 - this.labelWidth),
15508 } else if ( this.fieldLabel.length) {
15515 cls: 'control-label box-input-label',
15516 //cls : 'input-group-addon',
15517 html : this.fieldLabel
15527 Roo.log(" no label && no align");
15542 html: this.boxLabel
15549 inputEl: function ()
15551 return this.el.select('input.roo-radio',true).first();
15553 onClick : function()
15555 this.setChecked(true);
15558 setChecked : function(state,suppressEvent)
15561 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
15562 v.dom.checked = false;
15566 this.checked = state;
15567 this.inputEl().dom.checked = state;
15569 if(suppressEvent !== true){
15570 this.fireEvent('check', this, state);
15573 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15577 getGroupValue : function()
15580 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
15581 if(v.dom.checked == true){
15582 value = v.dom.value;
15590 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
15591 * @return {Mixed} value The field value
15593 getValue : function(){
15594 return this.getGroupValue();
15600 //<script type="text/javascript">
15603 * Based Ext JS Library 1.1.1
15604 * Copyright(c) 2006-2007, Ext JS, LLC.
15610 * @class Roo.HtmlEditorCore
15611 * @extends Roo.Component
15612 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
15614 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
15617 Roo.HtmlEditorCore = function(config){
15620 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
15623 * @event initialize
15624 * Fires when the editor is fully initialized (including the iframe)
15625 * @param {Roo.HtmlEditorCore} this
15630 * Fires when the editor is first receives the focus. Any insertion must wait
15631 * until after this event.
15632 * @param {Roo.HtmlEditorCore} this
15636 * @event beforesync
15637 * Fires before the textarea is updated with content from the editor iframe. Return false
15638 * to cancel the sync.
15639 * @param {Roo.HtmlEditorCore} this
15640 * @param {String} html
15644 * @event beforepush
15645 * Fires before the iframe editor is updated with content from the textarea. Return false
15646 * to cancel the push.
15647 * @param {Roo.HtmlEditorCore} this
15648 * @param {String} html
15653 * Fires when the textarea is updated with content from the editor iframe.
15654 * @param {Roo.HtmlEditorCore} this
15655 * @param {String} html
15660 * Fires when the iframe editor is updated with content from the textarea.
15661 * @param {Roo.HtmlEditorCore} this
15662 * @param {String} html
15667 * @event editorevent
15668 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
15669 * @param {Roo.HtmlEditorCore} this
15677 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
15681 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
15687 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
15692 * @cfg {Number} height (in pixels)
15696 * @cfg {Number} width (in pixels)
15701 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
15704 stylesheets: false,
15709 // private properties
15710 validationEvent : false,
15712 initialized : false,
15714 sourceEditMode : false,
15715 onFocus : Roo.emptyFn,
15717 hideMode:'offsets',
15725 * Protected method that will not generally be called directly. It
15726 * is called when the editor initializes the iframe with HTML contents. Override this method if you
15727 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
15729 getDocMarkup : function(){
15732 Roo.log(this.stylesheets);
15734 // inherit styels from page...??
15735 if (this.stylesheets === false) {
15737 Roo.get(document.head).select('style').each(function(node) {
15738 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
15741 Roo.get(document.head).select('link').each(function(node) {
15742 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
15745 } else if (!this.stylesheets.length) {
15747 st = '<style type="text/css">' +
15748 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
15751 Roo.each(this.stylesheets, function(s) {
15752 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
15757 st += '<style type="text/css">' +
15758 'IMG { cursor: pointer } ' +
15762 return '<html><head>' + st +
15763 //<style type="text/css">' +
15764 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
15766 ' </head><body class="roo-htmleditor-body"></body></html>';
15770 onRender : function(ct, position)
15773 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
15774 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
15777 this.el.dom.style.border = '0 none';
15778 this.el.dom.setAttribute('tabIndex', -1);
15779 this.el.addClass('x-hidden hide');
15783 if(Roo.isIE){ // fix IE 1px bogus margin
15784 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
15788 this.frameId = Roo.id();
15792 var iframe = this.owner.wrap.createChild({
15794 cls: 'form-control', // bootstrap..
15796 name: this.frameId,
15797 frameBorder : 'no',
15798 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
15803 this.iframe = iframe.dom;
15805 this.assignDocWin();
15807 this.doc.designMode = 'on';
15810 this.doc.write(this.getDocMarkup());
15814 var task = { // must defer to wait for browser to be ready
15816 //console.log("run task?" + this.doc.readyState);
15817 this.assignDocWin();
15818 if(this.doc.body || this.doc.readyState == 'complete'){
15820 this.doc.designMode="on";
15824 Roo.TaskMgr.stop(task);
15825 this.initEditor.defer(10, this);
15832 Roo.TaskMgr.start(task);
15839 onResize : function(w, h)
15841 Roo.log('resize: ' +w + ',' + h );
15842 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
15846 if(typeof w == 'number'){
15848 this.iframe.style.width = w + 'px';
15850 if(typeof h == 'number'){
15852 this.iframe.style.height = h + 'px';
15854 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
15861 * Toggles the editor between standard and source edit mode.
15862 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
15864 toggleSourceEdit : function(sourceEditMode){
15866 this.sourceEditMode = sourceEditMode === true;
15868 if(this.sourceEditMode){
15870 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
15873 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
15874 //this.iframe.className = '';
15877 //this.setSize(this.owner.wrap.getSize());
15878 //this.fireEvent('editmodechange', this, this.sourceEditMode);
15885 * Protected method that will not generally be called directly. If you need/want
15886 * custom HTML cleanup, this is the method you should override.
15887 * @param {String} html The HTML to be cleaned
15888 * return {String} The cleaned HTML
15890 cleanHtml : function(html){
15891 html = String(html);
15892 if(html.length > 5){
15893 if(Roo.isSafari){ // strip safari nonsense
15894 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
15897 if(html == ' '){
15904 * HTML Editor -> Textarea
15905 * Protected method that will not generally be called directly. Syncs the contents
15906 * of the editor iframe with the textarea.
15908 syncValue : function(){
15909 if(this.initialized){
15910 var bd = (this.doc.body || this.doc.documentElement);
15911 //this.cleanUpPaste(); -- this is done else where and causes havoc..
15912 var html = bd.innerHTML;
15914 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
15915 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
15917 html = '<div style="'+m[0]+'">' + html + '</div>';
15920 html = this.cleanHtml(html);
15921 // fix up the special chars.. normaly like back quotes in word...
15922 // however we do not want to do this with chinese..
15923 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
15924 var cc = b.charCodeAt();
15926 (cc >= 0x4E00 && cc < 0xA000 ) ||
15927 (cc >= 0x3400 && cc < 0x4E00 ) ||
15928 (cc >= 0xf900 && cc < 0xfb00 )
15934 if(this.owner.fireEvent('beforesync', this, html) !== false){
15935 this.el.dom.value = html;
15936 this.owner.fireEvent('sync', this, html);
15942 * Protected method that will not generally be called directly. Pushes the value of the textarea
15943 * into the iframe editor.
15945 pushValue : function(){
15946 if(this.initialized){
15947 var v = this.el.dom.value.trim();
15949 // if(v.length < 1){
15953 if(this.owner.fireEvent('beforepush', this, v) !== false){
15954 var d = (this.doc.body || this.doc.documentElement);
15956 this.cleanUpPaste();
15957 this.el.dom.value = d.innerHTML;
15958 this.owner.fireEvent('push', this, v);
15964 deferFocus : function(){
15965 this.focus.defer(10, this);
15969 focus : function(){
15970 if(this.win && !this.sourceEditMode){
15977 assignDocWin: function()
15979 var iframe = this.iframe;
15982 this.doc = iframe.contentWindow.document;
15983 this.win = iframe.contentWindow;
15985 if (!Roo.get(this.frameId)) {
15988 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
15989 this.win = Roo.get(this.frameId).dom.contentWindow;
15994 initEditor : function(){
15995 //console.log("INIT EDITOR");
15996 this.assignDocWin();
16000 this.doc.designMode="on";
16002 this.doc.write(this.getDocMarkup());
16005 var dbody = (this.doc.body || this.doc.documentElement);
16006 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16007 // this copies styles from the containing element into thsi one..
16008 // not sure why we need all of this..
16009 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16011 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16012 //ss['background-attachment'] = 'fixed'; // w3c
16013 dbody.bgProperties = 'fixed'; // ie
16014 //Roo.DomHelper.applyStyles(dbody, ss);
16015 Roo.EventManager.on(this.doc, {
16016 //'mousedown': this.onEditorEvent,
16017 'mouseup': this.onEditorEvent,
16018 'dblclick': this.onEditorEvent,
16019 'click': this.onEditorEvent,
16020 'keyup': this.onEditorEvent,
16025 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16027 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16028 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16030 this.initialized = true;
16032 this.owner.fireEvent('initialize', this);
16037 onDestroy : function(){
16043 //for (var i =0; i < this.toolbars.length;i++) {
16044 // // fixme - ask toolbars for heights?
16045 // this.toolbars[i].onDestroy();
16048 //this.wrap.dom.innerHTML = '';
16049 //this.wrap.remove();
16054 onFirstFocus : function(){
16056 this.assignDocWin();
16059 this.activated = true;
16062 if(Roo.isGecko){ // prevent silly gecko errors
16064 var s = this.win.getSelection();
16065 if(!s.focusNode || s.focusNode.nodeType != 3){
16066 var r = s.getRangeAt(0);
16067 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16072 this.execCmd('useCSS', true);
16073 this.execCmd('styleWithCSS', false);
16076 this.owner.fireEvent('activate', this);
16080 adjustFont: function(btn){
16081 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16082 //if(Roo.isSafari){ // safari
16085 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16086 if(Roo.isSafari){ // safari
16087 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16088 v = (v < 10) ? 10 : v;
16089 v = (v > 48) ? 48 : v;
16090 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16095 v = Math.max(1, v+adjust);
16097 this.execCmd('FontSize', v );
16100 onEditorEvent : function(e){
16101 this.owner.fireEvent('editorevent', this, e);
16102 // this.updateToolbar();
16103 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16106 insertTag : function(tg)
16108 // could be a bit smarter... -> wrap the current selected tRoo..
16109 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16111 range = this.createRange(this.getSelection());
16112 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16113 wrappingNode.appendChild(range.extractContents());
16114 range.insertNode(wrappingNode);
16121 this.execCmd("formatblock", tg);
16125 insertText : function(txt)
16129 var range = this.createRange();
16130 range.deleteContents();
16131 //alert(Sender.getAttribute('label'));
16133 range.insertNode(this.doc.createTextNode(txt));
16139 * Executes a Midas editor command on the editor document and performs necessary focus and
16140 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16141 * @param {String} cmd The Midas command
16142 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16144 relayCmd : function(cmd, value){
16146 this.execCmd(cmd, value);
16147 this.owner.fireEvent('editorevent', this);
16148 //this.updateToolbar();
16149 this.owner.deferFocus();
16153 * Executes a Midas editor command directly on the editor document.
16154 * For visual commands, you should use {@link #relayCmd} instead.
16155 * <b>This should only be called after the editor is initialized.</b>
16156 * @param {String} cmd The Midas command
16157 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16159 execCmd : function(cmd, value){
16160 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16167 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16169 * @param {String} text | dom node..
16171 insertAtCursor : function(text)
16176 if(!this.activated){
16182 var r = this.doc.selection.createRange();
16193 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16197 // from jquery ui (MIT licenced)
16199 var win = this.win;
16201 if (win.getSelection && win.getSelection().getRangeAt) {
16202 range = win.getSelection().getRangeAt(0);
16203 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16204 range.insertNode(node);
16205 } else if (win.document.selection && win.document.selection.createRange) {
16206 // no firefox support
16207 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16208 win.document.selection.createRange().pasteHTML(txt);
16210 // no firefox support
16211 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16212 this.execCmd('InsertHTML', txt);
16221 mozKeyPress : function(e){
16223 var c = e.getCharCode(), cmd;
16226 c = String.fromCharCode(c).toLowerCase();
16240 this.cleanUpPaste.defer(100, this);
16248 e.preventDefault();
16256 fixKeys : function(){ // load time branching for fastest keydown performance
16258 return function(e){
16259 var k = e.getKey(), r;
16262 r = this.doc.selection.createRange();
16265 r.pasteHTML('    ');
16272 r = this.doc.selection.createRange();
16274 var target = r.parentElement();
16275 if(!target || target.tagName.toLowerCase() != 'li'){
16277 r.pasteHTML('<br />');
16283 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16284 this.cleanUpPaste.defer(100, this);
16290 }else if(Roo.isOpera){
16291 return function(e){
16292 var k = e.getKey();
16296 this.execCmd('InsertHTML','    ');
16299 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16300 this.cleanUpPaste.defer(100, this);
16305 }else if(Roo.isSafari){
16306 return function(e){
16307 var k = e.getKey();
16311 this.execCmd('InsertText','\t');
16315 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16316 this.cleanUpPaste.defer(100, this);
16324 getAllAncestors: function()
16326 var p = this.getSelectedNode();
16329 a.push(p); // push blank onto stack..
16330 p = this.getParentElement();
16334 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
16338 a.push(this.doc.body);
16342 lastSelNode : false,
16345 getSelection : function()
16347 this.assignDocWin();
16348 return Roo.isIE ? this.doc.selection : this.win.getSelection();
16351 getSelectedNode: function()
16353 // this may only work on Gecko!!!
16355 // should we cache this!!!!
16360 var range = this.createRange(this.getSelection()).cloneRange();
16363 var parent = range.parentElement();
16365 var testRange = range.duplicate();
16366 testRange.moveToElementText(parent);
16367 if (testRange.inRange(range)) {
16370 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
16373 parent = parent.parentElement;
16378 // is ancestor a text element.
16379 var ac = range.commonAncestorContainer;
16380 if (ac.nodeType == 3) {
16381 ac = ac.parentNode;
16384 var ar = ac.childNodes;
16387 var other_nodes = [];
16388 var has_other_nodes = false;
16389 for (var i=0;i<ar.length;i++) {
16390 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
16393 // fullly contained node.
16395 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
16400 // probably selected..
16401 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
16402 other_nodes.push(ar[i]);
16406 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
16411 has_other_nodes = true;
16413 if (!nodes.length && other_nodes.length) {
16414 nodes= other_nodes;
16416 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
16422 createRange: function(sel)
16424 // this has strange effects when using with
16425 // top toolbar - not sure if it's a great idea.
16426 //this.editor.contentWindow.focus();
16427 if (typeof sel != "undefined") {
16429 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
16431 return this.doc.createRange();
16434 return this.doc.createRange();
16437 getParentElement: function()
16440 this.assignDocWin();
16441 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
16443 var range = this.createRange(sel);
16446 var p = range.commonAncestorContainer;
16447 while (p.nodeType == 3) { // text node
16458 * Range intersection.. the hard stuff...
16462 * [ -- selected range --- ]
16466 * if end is before start or hits it. fail.
16467 * if start is after end or hits it fail.
16469 * if either hits (but other is outside. - then it's not
16475 // @see http://www.thismuchiknow.co.uk/?p=64.
16476 rangeIntersectsNode : function(range, node)
16478 var nodeRange = node.ownerDocument.createRange();
16480 nodeRange.selectNode(node);
16482 nodeRange.selectNodeContents(node);
16485 var rangeStartRange = range.cloneRange();
16486 rangeStartRange.collapse(true);
16488 var rangeEndRange = range.cloneRange();
16489 rangeEndRange.collapse(false);
16491 var nodeStartRange = nodeRange.cloneRange();
16492 nodeStartRange.collapse(true);
16494 var nodeEndRange = nodeRange.cloneRange();
16495 nodeEndRange.collapse(false);
16497 return rangeStartRange.compareBoundaryPoints(
16498 Range.START_TO_START, nodeEndRange) == -1 &&
16499 rangeEndRange.compareBoundaryPoints(
16500 Range.START_TO_START, nodeStartRange) == 1;
16504 rangeCompareNode : function(range, node)
16506 var nodeRange = node.ownerDocument.createRange();
16508 nodeRange.selectNode(node);
16510 nodeRange.selectNodeContents(node);
16514 range.collapse(true);
16516 nodeRange.collapse(true);
16518 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
16519 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
16521 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
16523 var nodeIsBefore = ss == 1;
16524 var nodeIsAfter = ee == -1;
16526 if (nodeIsBefore && nodeIsAfter)
16528 if (!nodeIsBefore && nodeIsAfter)
16529 return 1; //right trailed.
16531 if (nodeIsBefore && !nodeIsAfter)
16532 return 2; // left trailed.
16537 // private? - in a new class?
16538 cleanUpPaste : function()
16540 // cleans up the whole document..
16541 Roo.log('cleanuppaste');
16543 this.cleanUpChildren(this.doc.body);
16544 var clean = this.cleanWordChars(this.doc.body.innerHTML);
16545 if (clean != this.doc.body.innerHTML) {
16546 this.doc.body.innerHTML = clean;
16551 cleanWordChars : function(input) {// change the chars to hex code
16552 var he = Roo.HtmlEditorCore;
16554 var output = input;
16555 Roo.each(he.swapCodes, function(sw) {
16556 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
16558 output = output.replace(swapper, sw[1]);
16565 cleanUpChildren : function (n)
16567 if (!n.childNodes.length) {
16570 for (var i = n.childNodes.length-1; i > -1 ; i--) {
16571 this.cleanUpChild(n.childNodes[i]);
16578 cleanUpChild : function (node)
16581 //console.log(node);
16582 if (node.nodeName == "#text") {
16583 // clean up silly Windows -- stuff?
16586 if (node.nodeName == "#comment") {
16587 node.parentNode.removeChild(node);
16588 // clean up silly Windows -- stuff?
16592 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
16594 node.parentNode.removeChild(node);
16599 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
16601 // remove <a name=....> as rendering on yahoo mailer is borked with this.
16602 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
16604 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
16605 // remove_keep_children = true;
16608 if (remove_keep_children) {
16609 this.cleanUpChildren(node);
16610 // inserts everything just before this node...
16611 while (node.childNodes.length) {
16612 var cn = node.childNodes[0];
16613 node.removeChild(cn);
16614 node.parentNode.insertBefore(cn, node);
16616 node.parentNode.removeChild(node);
16620 if (!node.attributes || !node.attributes.length) {
16621 this.cleanUpChildren(node);
16625 function cleanAttr(n,v)
16628 if (v.match(/^\./) || v.match(/^\//)) {
16631 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
16634 if (v.match(/^#/)) {
16637 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
16638 node.removeAttribute(n);
16642 function cleanStyle(n,v)
16644 if (v.match(/expression/)) { //XSS?? should we even bother..
16645 node.removeAttribute(n);
16648 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
16649 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
16652 var parts = v.split(/;/);
16655 Roo.each(parts, function(p) {
16656 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
16660 var l = p.split(':').shift().replace(/\s+/g,'');
16661 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
16663 if ( cblack.indexOf(l) > -1) {
16664 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
16665 //node.removeAttribute(n);
16669 // only allow 'c whitelisted system attributes'
16670 if ( cwhite.length && cwhite.indexOf(l) < 0) {
16671 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
16672 //node.removeAttribute(n);
16682 if (clean.length) {
16683 node.setAttribute(n, clean.join(';'));
16685 node.removeAttribute(n);
16691 for (var i = node.attributes.length-1; i > -1 ; i--) {
16692 var a = node.attributes[i];
16695 if (a.name.toLowerCase().substr(0,2)=='on') {
16696 node.removeAttribute(a.name);
16699 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
16700 node.removeAttribute(a.name);
16703 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
16704 cleanAttr(a.name,a.value); // fixme..
16707 if (a.name == 'style') {
16708 cleanStyle(a.name,a.value);
16711 /// clean up MS crap..
16712 // tecnically this should be a list of valid class'es..
16715 if (a.name == 'class') {
16716 if (a.value.match(/^Mso/)) {
16717 node.className = '';
16720 if (a.value.match(/body/)) {
16721 node.className = '';
16732 this.cleanUpChildren(node);
16737 * Clean up MS wordisms...
16739 cleanWord : function(node)
16742 var cleanWordChildren = function()
16744 if (!node.childNodes.length) {
16747 for (var i = node.childNodes.length-1; i > -1 ; i--) {
16748 _t.cleanWord(node.childNodes[i]);
16754 this.cleanWord(this.doc.body);
16757 if (node.nodeName == "#text") {
16758 // clean up silly Windows -- stuff?
16761 if (node.nodeName == "#comment") {
16762 node.parentNode.removeChild(node);
16763 // clean up silly Windows -- stuff?
16767 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
16768 node.parentNode.removeChild(node);
16772 // remove - but keep children..
16773 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
16774 while (node.childNodes.length) {
16775 var cn = node.childNodes[0];
16776 node.removeChild(cn);
16777 node.parentNode.insertBefore(cn, node);
16779 node.parentNode.removeChild(node);
16780 cleanWordChildren();
16784 if (node.className.length) {
16786 var cn = node.className.split(/\W+/);
16788 Roo.each(cn, function(cls) {
16789 if (cls.match(/Mso[a-zA-Z]+/)) {
16794 node.className = cna.length ? cna.join(' ') : '';
16796 node.removeAttribute("class");
16800 if (node.hasAttribute("lang")) {
16801 node.removeAttribute("lang");
16804 if (node.hasAttribute("style")) {
16806 var styles = node.getAttribute("style").split(";");
16808 Roo.each(styles, function(s) {
16809 if (!s.match(/:/)) {
16812 var kv = s.split(":");
16813 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
16816 // what ever is left... we allow.
16819 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
16820 if (!nstyle.length) {
16821 node.removeAttribute('style');
16825 cleanWordChildren();
16829 domToHTML : function(currentElement, depth, nopadtext) {
16831 depth = depth || 0;
16832 nopadtext = nopadtext || false;
16834 if (!currentElement) {
16835 return this.domToHTML(this.doc.body);
16838 //Roo.log(currentElement);
16840 var allText = false;
16841 var nodeName = currentElement.nodeName;
16842 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
16844 if (nodeName == '#text') {
16845 return currentElement.nodeValue;
16850 if (nodeName != 'BODY') {
16853 // Prints the node tagName, such as <A>, <IMG>, etc
16856 for(i = 0; i < currentElement.attributes.length;i++) {
16858 var aname = currentElement.attributes.item(i).name;
16859 if (!currentElement.attributes.item(i).value.length) {
16862 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
16865 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
16874 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
16877 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
16882 // Traverse the tree
16884 var currentElementChild = currentElement.childNodes.item(i);
16885 var allText = true;
16886 var innerHTML = '';
16888 while (currentElementChild) {
16889 // Formatting code (indent the tree so it looks nice on the screen)
16890 var nopad = nopadtext;
16891 if (lastnode == 'SPAN') {
16895 if (currentElementChild.nodeName == '#text') {
16896 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
16897 if (!nopad && toadd.length > 80) {
16898 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
16900 innerHTML += toadd;
16903 currentElementChild = currentElement.childNodes.item(i);
16909 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
16911 // Recursively traverse the tree structure of the child node
16912 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
16913 lastnode = currentElementChild.nodeName;
16915 currentElementChild=currentElement.childNodes.item(i);
16921 // The remaining code is mostly for formatting the tree
16922 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
16927 ret+= "</"+tagName+">";
16933 // hide stuff that is not compatible
16947 * @event specialkey
16951 * @cfg {String} fieldClass @hide
16954 * @cfg {String} focusClass @hide
16957 * @cfg {String} autoCreate @hide
16960 * @cfg {String} inputType @hide
16963 * @cfg {String} invalidClass @hide
16966 * @cfg {String} invalidText @hide
16969 * @cfg {String} msgFx @hide
16972 * @cfg {String} validateOnBlur @hide
16976 Roo.HtmlEditorCore.white = [
16977 'area', 'br', 'img', 'input', 'hr', 'wbr',
16979 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
16980 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
16981 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
16982 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
16983 'table', 'ul', 'xmp',
16985 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
16988 'dir', 'menu', 'ol', 'ul', 'dl',
16994 Roo.HtmlEditorCore.black = [
16995 // 'embed', 'object', // enable - backend responsiblity to clean thiese
16997 'base', 'basefont', 'bgsound', 'blink', 'body',
16998 'frame', 'frameset', 'head', 'html', 'ilayer',
16999 'iframe', 'layer', 'link', 'meta', 'object',
17000 'script', 'style' ,'title', 'xml' // clean later..
17002 Roo.HtmlEditorCore.clean = [
17003 'script', 'style', 'title', 'xml'
17005 Roo.HtmlEditorCore.remove = [
17010 Roo.HtmlEditorCore.ablack = [
17014 Roo.HtmlEditorCore.aclean = [
17015 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17019 Roo.HtmlEditorCore.pwhite= [
17020 'http', 'https', 'mailto'
17023 // white listed style attributes.
17024 Roo.HtmlEditorCore.cwhite= [
17025 // 'text-align', /// default is to allow most things..
17031 // black listed style attributes.
17032 Roo.HtmlEditorCore.cblack= [
17033 // 'font-size' -- this can be set by the project
17037 Roo.HtmlEditorCore.swapCodes =[
17056 * @class Roo.bootstrap.HtmlEditor
17057 * @extends Roo.bootstrap.TextArea
17058 * Bootstrap HtmlEditor class
17061 * Create a new HtmlEditor
17062 * @param {Object} config The config object
17065 Roo.bootstrap.HtmlEditor = function(config){
17066 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17067 if (!this.toolbars) {
17068 this.toolbars = [];
17070 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17073 * @event initialize
17074 * Fires when the editor is fully initialized (including the iframe)
17075 * @param {HtmlEditor} this
17080 * Fires when the editor is first receives the focus. Any insertion must wait
17081 * until after this event.
17082 * @param {HtmlEditor} this
17086 * @event beforesync
17087 * Fires before the textarea is updated with content from the editor iframe. Return false
17088 * to cancel the sync.
17089 * @param {HtmlEditor} this
17090 * @param {String} html
17094 * @event beforepush
17095 * Fires before the iframe editor is updated with content from the textarea. Return false
17096 * to cancel the push.
17097 * @param {HtmlEditor} this
17098 * @param {String} html
17103 * Fires when the textarea is updated with content from the editor iframe.
17104 * @param {HtmlEditor} this
17105 * @param {String} html
17110 * Fires when the iframe editor is updated with content from the textarea.
17111 * @param {HtmlEditor} this
17112 * @param {String} html
17116 * @event editmodechange
17117 * Fires when the editor switches edit modes
17118 * @param {HtmlEditor} this
17119 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17121 editmodechange: true,
17123 * @event editorevent
17124 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17125 * @param {HtmlEditor} this
17129 * @event firstfocus
17130 * Fires when on first focus - needed by toolbars..
17131 * @param {HtmlEditor} this
17136 * Auto save the htmlEditor value as a file into Events
17137 * @param {HtmlEditor} this
17141 * @event savedpreview
17142 * preview the saved version of htmlEditor
17143 * @param {HtmlEditor} this
17150 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17154 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17159 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17164 * @cfg {Number} height (in pixels)
17168 * @cfg {Number} width (in pixels)
17173 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17176 stylesheets: false,
17181 // private properties
17182 validationEvent : false,
17184 initialized : false,
17187 onFocus : Roo.emptyFn,
17189 hideMode:'offsets',
17192 tbContainer : false,
17194 toolbarContainer :function() {
17195 return this.wrap.select('.x-html-editor-tb',true).first();
17199 * Protected method that will not generally be called directly. It
17200 * is called when the editor creates its toolbar. Override this method if you need to
17201 * add custom toolbar buttons.
17202 * @param {HtmlEditor} editor
17204 createToolbar : function(){
17206 Roo.log("create toolbars");
17208 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17209 this.toolbars[0].render(this.toolbarContainer());
17213 // if (!editor.toolbars || !editor.toolbars.length) {
17214 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17217 // for (var i =0 ; i < editor.toolbars.length;i++) {
17218 // editor.toolbars[i] = Roo.factory(
17219 // typeof(editor.toolbars[i]) == 'string' ?
17220 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
17221 // Roo.bootstrap.HtmlEditor);
17222 // editor.toolbars[i].init(editor);
17228 onRender : function(ct, position)
17230 // Roo.log("Call onRender: " + this.xtype);
17232 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17234 this.wrap = this.inputEl().wrap({
17235 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17238 this.editorcore.onRender(ct, position);
17240 if (this.resizable) {
17241 this.resizeEl = new Roo.Resizable(this.wrap, {
17245 minHeight : this.height,
17246 height: this.height,
17247 handles : this.resizable,
17250 resize : function(r, w, h) {
17251 _t.onResize(w,h); // -something
17257 this.createToolbar(this);
17260 if(!this.width && this.resizable){
17261 this.setSize(this.wrap.getSize());
17263 if (this.resizeEl) {
17264 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17265 // should trigger onReize..
17271 onResize : function(w, h)
17273 Roo.log('resize: ' +w + ',' + h );
17274 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17278 if(this.inputEl() ){
17279 if(typeof w == 'number'){
17280 var aw = w - this.wrap.getFrameWidth('lr');
17281 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17284 if(typeof h == 'number'){
17285 var tbh = -11; // fixme it needs to tool bar size!
17286 for (var i =0; i < this.toolbars.length;i++) {
17287 // fixme - ask toolbars for heights?
17288 tbh += this.toolbars[i].el.getHeight();
17289 //if (this.toolbars[i].footer) {
17290 // tbh += this.toolbars[i].footer.el.getHeight();
17298 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17299 ah -= 5; // knock a few pixes off for look..
17300 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17304 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17305 this.editorcore.onResize(ew,eh);
17310 * Toggles the editor between standard and source edit mode.
17311 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17313 toggleSourceEdit : function(sourceEditMode)
17315 this.editorcore.toggleSourceEdit(sourceEditMode);
17317 if(this.editorcore.sourceEditMode){
17318 Roo.log('editor - showing textarea');
17321 // Roo.log(this.syncValue());
17323 this.inputEl().removeClass(['hide', 'x-hidden']);
17324 this.inputEl().dom.removeAttribute('tabIndex');
17325 this.inputEl().focus();
17327 Roo.log('editor - hiding textarea');
17329 // Roo.log(this.pushValue());
17332 this.inputEl().addClass(['hide', 'x-hidden']);
17333 this.inputEl().dom.setAttribute('tabIndex', -1);
17334 //this.deferFocus();
17337 if(this.resizable){
17338 this.setSize(this.wrap.getSize());
17341 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
17344 // private (for BoxComponent)
17345 adjustSize : Roo.BoxComponent.prototype.adjustSize,
17347 // private (for BoxComponent)
17348 getResizeEl : function(){
17352 // private (for BoxComponent)
17353 getPositionEl : function(){
17358 initEvents : function(){
17359 this.originalValue = this.getValue();
17363 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17366 // markInvalid : Roo.emptyFn,
17368 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17371 // clearInvalid : Roo.emptyFn,
17373 setValue : function(v){
17374 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
17375 this.editorcore.pushValue();
17380 deferFocus : function(){
17381 this.focus.defer(10, this);
17385 focus : function(){
17386 this.editorcore.focus();
17392 onDestroy : function(){
17398 for (var i =0; i < this.toolbars.length;i++) {
17399 // fixme - ask toolbars for heights?
17400 this.toolbars[i].onDestroy();
17403 this.wrap.dom.innerHTML = '';
17404 this.wrap.remove();
17409 onFirstFocus : function(){
17410 //Roo.log("onFirstFocus");
17411 this.editorcore.onFirstFocus();
17412 for (var i =0; i < this.toolbars.length;i++) {
17413 this.toolbars[i].onFirstFocus();
17419 syncValue : function()
17421 this.editorcore.syncValue();
17424 pushValue : function()
17426 this.editorcore.pushValue();
17430 // hide stuff that is not compatible
17444 * @event specialkey
17448 * @cfg {String} fieldClass @hide
17451 * @cfg {String} focusClass @hide
17454 * @cfg {String} autoCreate @hide
17457 * @cfg {String} inputType @hide
17460 * @cfg {String} invalidClass @hide
17463 * @cfg {String} invalidText @hide
17466 * @cfg {String} msgFx @hide
17469 * @cfg {String} validateOnBlur @hide
17478 Roo.namespace('Roo.bootstrap.htmleditor');
17480 * @class Roo.bootstrap.HtmlEditorToolbar1
17485 new Roo.bootstrap.HtmlEditor({
17488 new Roo.bootstrap.HtmlEditorToolbar1({
17489 disable : { fonts: 1 , format: 1, ..., ... , ...],
17495 * @cfg {Object} disable List of elements to disable..
17496 * @cfg {Array} btns List of additional buttons.
17500 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
17503 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
17506 Roo.apply(this, config);
17508 // default disabled, based on 'good practice'..
17509 this.disable = this.disable || {};
17510 Roo.applyIf(this.disable, {
17513 specialElements : true
17515 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
17517 this.editor = config.editor;
17518 this.editorcore = config.editor.editorcore;
17520 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
17522 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
17523 // dont call parent... till later.
17525 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
17530 editorcore : false,
17535 "h1","h2","h3","h4","h5","h6",
17537 "abbr", "acronym", "address", "cite", "samp", "var",
17541 onRender : function(ct, position)
17543 // Roo.log("Call onRender: " + this.xtype);
17545 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
17547 this.el.dom.style.marginBottom = '0';
17549 var editorcore = this.editorcore;
17550 var editor= this.editor;
17553 var btn = function(id,cmd , toggle, handler){
17555 var event = toggle ? 'toggle' : 'click';
17560 xns: Roo.bootstrap,
17563 enableToggle:toggle !== false,
17565 pressed : toggle ? false : null,
17568 a.listeners[toggle ? 'toggle' : 'click'] = function() {
17569 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
17578 xns: Roo.bootstrap,
17579 glyphicon : 'font',
17583 xns: Roo.bootstrap,
17587 Roo.each(this.formats, function(f) {
17588 style.menu.items.push({
17590 xns: Roo.bootstrap,
17591 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
17596 editorcore.insertTag(this.tagname);
17603 children.push(style);
17606 btn('bold',false,true);
17607 btn('italic',false,true);
17608 btn('align-left', 'justifyleft',true);
17609 btn('align-center', 'justifycenter',true);
17610 btn('align-right' , 'justifyright',true);
17611 btn('link', false, false, function(btn) {
17612 //Roo.log("create link?");
17613 var url = prompt(this.createLinkText, this.defaultLinkValue);
17614 if(url && url != 'http:/'+'/'){
17615 this.editorcore.relayCmd('createlink', url);
17618 btn('list','insertunorderedlist',true);
17619 btn('pencil', false,true, function(btn){
17622 this.toggleSourceEdit(btn.pressed);
17628 xns: Roo.bootstrap,
17633 xns: Roo.bootstrap,
17638 cog.menu.items.push({
17640 xns: Roo.bootstrap,
17641 html : Clean styles,
17646 editorcore.insertTag(this.tagname);
17655 this.xtype = 'NavSimplebar';
17657 for(var i=0;i< children.length;i++) {
17659 this.buttons.add(this.addxtypeChild(children[i]));
17663 editor.on('editorevent', this.updateToolbar, this);
17665 onBtnClick : function(id)
17667 this.editorcore.relayCmd(id);
17668 this.editorcore.focus();
17672 * Protected method that will not generally be called directly. It triggers
17673 * a toolbar update by reading the markup state of the current selection in the editor.
17675 updateToolbar: function(){
17677 if(!this.editorcore.activated){
17678 this.editor.onFirstFocus(); // is this neeed?
17682 var btns = this.buttons;
17683 var doc = this.editorcore.doc;
17684 btns.get('bold').setActive(doc.queryCommandState('bold'));
17685 btns.get('italic').setActive(doc.queryCommandState('italic'));
17686 //btns.get('underline').setActive(doc.queryCommandState('underline'));
17688 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
17689 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
17690 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
17692 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
17693 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
17696 var ans = this.editorcore.getAllAncestors();
17697 if (this.formatCombo) {
17700 var store = this.formatCombo.store;
17701 this.formatCombo.setValue("");
17702 for (var i =0; i < ans.length;i++) {
17703 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
17705 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
17713 // hides menus... - so this cant be on a menu...
17714 Roo.bootstrap.MenuMgr.hideAll();
17716 Roo.bootstrap.MenuMgr.hideAll();
17717 //this.editorsyncValue();
17719 onFirstFocus: function() {
17720 this.buttons.each(function(item){
17724 toggleSourceEdit : function(sourceEditMode){
17727 if(sourceEditMode){
17728 Roo.log("disabling buttons");
17729 this.buttons.each( function(item){
17730 if(item.cmd != 'pencil'){
17736 Roo.log("enabling buttons");
17737 if(this.editorcore.initialized){
17738 this.buttons.each( function(item){
17744 Roo.log("calling toggole on editor");
17745 // tell the editor that it's been pressed..
17746 this.editor.toggleSourceEdit(sourceEditMode);
17756 * @class Roo.bootstrap.Table.AbstractSelectionModel
17757 * @extends Roo.util.Observable
17758 * Abstract base class for grid SelectionModels. It provides the interface that should be
17759 * implemented by descendant classes. This class should not be directly instantiated.
17762 Roo.bootstrap.Table.AbstractSelectionModel = function(){
17763 this.locked = false;
17764 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
17768 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
17769 /** @ignore Called by the grid automatically. Do not call directly. */
17770 init : function(grid){
17776 * Locks the selections.
17779 this.locked = true;
17783 * Unlocks the selections.
17785 unlock : function(){
17786 this.locked = false;
17790 * Returns true if the selections are locked.
17791 * @return {Boolean}
17793 isLocked : function(){
17794 return this.locked;
17798 * @extends Roo.bootstrap.Table.AbstractSelectionModel
17799 * @class Roo.bootstrap.Table.RowSelectionModel
17800 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
17801 * It supports multiple selections and keyboard selection/navigation.
17803 * @param {Object} config
17806 Roo.bootstrap.Table.RowSelectionModel = function(config){
17807 Roo.apply(this, config);
17808 this.selections = new Roo.util.MixedCollection(false, function(o){
17813 this.lastActive = false;
17817 * @event selectionchange
17818 * Fires when the selection changes
17819 * @param {SelectionModel} this
17821 "selectionchange" : true,
17823 * @event afterselectionchange
17824 * Fires after the selection changes (eg. by key press or clicking)
17825 * @param {SelectionModel} this
17827 "afterselectionchange" : true,
17829 * @event beforerowselect
17830 * Fires when a row is selected being selected, return false to cancel.
17831 * @param {SelectionModel} this
17832 * @param {Number} rowIndex The selected index
17833 * @param {Boolean} keepExisting False if other selections will be cleared
17835 "beforerowselect" : true,
17838 * Fires when a row is selected.
17839 * @param {SelectionModel} this
17840 * @param {Number} rowIndex The selected index
17841 * @param {Roo.data.Record} r The record
17843 "rowselect" : true,
17845 * @event rowdeselect
17846 * Fires when a row is deselected.
17847 * @param {SelectionModel} this
17848 * @param {Number} rowIndex The selected index
17850 "rowdeselect" : true
17852 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
17853 this.locked = false;
17856 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
17858 * @cfg {Boolean} singleSelect
17859 * True to allow selection of only one row at a time (defaults to false)
17861 singleSelect : false,
17864 initEvents : function(){
17866 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
17867 this.grid.on("mousedown", this.handleMouseDown, this);
17868 }else{ // allow click to work like normal
17869 this.grid.on("rowclick", this.handleDragableRowClick, this);
17872 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
17873 "up" : function(e){
17875 this.selectPrevious(e.shiftKey);
17876 }else if(this.last !== false && this.lastActive !== false){
17877 var last = this.last;
17878 this.selectRange(this.last, this.lastActive-1);
17879 this.grid.getView().focusRow(this.lastActive);
17880 if(last !== false){
17884 this.selectFirstRow();
17886 this.fireEvent("afterselectionchange", this);
17888 "down" : function(e){
17890 this.selectNext(e.shiftKey);
17891 }else if(this.last !== false && this.lastActive !== false){
17892 var last = this.last;
17893 this.selectRange(this.last, this.lastActive+1);
17894 this.grid.getView().focusRow(this.lastActive);
17895 if(last !== false){
17899 this.selectFirstRow();
17901 this.fireEvent("afterselectionchange", this);
17906 var view = this.grid.view;
17907 view.on("refresh", this.onRefresh, this);
17908 view.on("rowupdated", this.onRowUpdated, this);
17909 view.on("rowremoved", this.onRemove, this);
17913 onRefresh : function(){
17914 var ds = this.grid.dataSource, i, v = this.grid.view;
17915 var s = this.selections;
17916 s.each(function(r){
17917 if((i = ds.indexOfId(r.id)) != -1){
17926 onRemove : function(v, index, r){
17927 this.selections.remove(r);
17931 onRowUpdated : function(v, index, r){
17932 if(this.isSelected(r)){
17933 v.onRowSelect(index);
17939 * @param {Array} records The records to select
17940 * @param {Boolean} keepExisting (optional) True to keep existing selections
17942 selectRecords : function(records, keepExisting){
17944 this.clearSelections();
17946 var ds = this.grid.dataSource;
17947 for(var i = 0, len = records.length; i < len; i++){
17948 this.selectRow(ds.indexOf(records[i]), true);
17953 * Gets the number of selected rows.
17956 getCount : function(){
17957 return this.selections.length;
17961 * Selects the first row in the grid.
17963 selectFirstRow : function(){
17968 * Select the last row.
17969 * @param {Boolean} keepExisting (optional) True to keep existing selections
17971 selectLastRow : function(keepExisting){
17972 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
17976 * Selects the row immediately following the last selected row.
17977 * @param {Boolean} keepExisting (optional) True to keep existing selections
17979 selectNext : function(keepExisting){
17980 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
17981 this.selectRow(this.last+1, keepExisting);
17982 this.grid.getView().focusRow(this.last);
17987 * Selects the row that precedes the last selected row.
17988 * @param {Boolean} keepExisting (optional) True to keep existing selections
17990 selectPrevious : function(keepExisting){
17992 this.selectRow(this.last-1, keepExisting);
17993 this.grid.getView().focusRow(this.last);
17998 * Returns the selected records
17999 * @return {Array} Array of selected records
18001 getSelections : function(){
18002 return [].concat(this.selections.items);
18006 * Returns the first selected record.
18009 getSelected : function(){
18010 return this.selections.itemAt(0);
18015 * Clears all selections.
18017 clearSelections : function(fast){
18018 if(this.locked) return;
18020 var ds = this.grid.dataSource;
18021 var s = this.selections;
18022 s.each(function(r){
18023 this.deselectRow(ds.indexOfId(r.id));
18027 this.selections.clear();
18034 * Selects all rows.
18036 selectAll : function(){
18037 if(this.locked) return;
18038 this.selections.clear();
18039 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18040 this.selectRow(i, true);
18045 * Returns True if there is a selection.
18046 * @return {Boolean}
18048 hasSelection : function(){
18049 return this.selections.length > 0;
18053 * Returns True if the specified row is selected.
18054 * @param {Number/Record} record The record or index of the record to check
18055 * @return {Boolean}
18057 isSelected : function(index){
18058 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18059 return (r && this.selections.key(r.id) ? true : false);
18063 * Returns True if the specified record id is selected.
18064 * @param {String} id The id of record to check
18065 * @return {Boolean}
18067 isIdSelected : function(id){
18068 return (this.selections.key(id) ? true : false);
18072 handleMouseDown : function(e, t){
18073 var view = this.grid.getView(), rowIndex;
18074 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18077 if(e.shiftKey && this.last !== false){
18078 var last = this.last;
18079 this.selectRange(last, rowIndex, e.ctrlKey);
18080 this.last = last; // reset the last
18081 view.focusRow(rowIndex);
18083 var isSelected = this.isSelected(rowIndex);
18084 if(e.button !== 0 && isSelected){
18085 view.focusRow(rowIndex);
18086 }else if(e.ctrlKey && isSelected){
18087 this.deselectRow(rowIndex);
18088 }else if(!isSelected){
18089 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18090 view.focusRow(rowIndex);
18093 this.fireEvent("afterselectionchange", this);
18096 handleDragableRowClick : function(grid, rowIndex, e)
18098 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18099 this.selectRow(rowIndex, false);
18100 grid.view.focusRow(rowIndex);
18101 this.fireEvent("afterselectionchange", this);
18106 * Selects multiple rows.
18107 * @param {Array} rows Array of the indexes of the row to select
18108 * @param {Boolean} keepExisting (optional) True to keep existing selections
18110 selectRows : function(rows, keepExisting){
18112 this.clearSelections();
18114 for(var i = 0, len = rows.length; i < len; i++){
18115 this.selectRow(rows[i], true);
18120 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18121 * @param {Number} startRow The index of the first row in the range
18122 * @param {Number} endRow The index of the last row in the range
18123 * @param {Boolean} keepExisting (optional) True to retain existing selections
18125 selectRange : function(startRow, endRow, keepExisting){
18126 if(this.locked) return;
18128 this.clearSelections();
18130 if(startRow <= endRow){
18131 for(var i = startRow; i <= endRow; i++){
18132 this.selectRow(i, true);
18135 for(var i = startRow; i >= endRow; i--){
18136 this.selectRow(i, true);
18142 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18143 * @param {Number} startRow The index of the first row in the range
18144 * @param {Number} endRow The index of the last row in the range
18146 deselectRange : function(startRow, endRow, preventViewNotify){
18147 if(this.locked) return;
18148 for(var i = startRow; i <= endRow; i++){
18149 this.deselectRow(i, preventViewNotify);
18155 * @param {Number} row The index of the row to select
18156 * @param {Boolean} keepExisting (optional) True to keep existing selections
18158 selectRow : function(index, keepExisting, preventViewNotify){
18159 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18160 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18161 if(!keepExisting || this.singleSelect){
18162 this.clearSelections();
18164 var r = this.grid.dataSource.getAt(index);
18165 this.selections.add(r);
18166 this.last = this.lastActive = index;
18167 if(!preventViewNotify){
18168 this.grid.getView().onRowSelect(index);
18170 this.fireEvent("rowselect", this, index, r);
18171 this.fireEvent("selectionchange", this);
18177 * @param {Number} row The index of the row to deselect
18179 deselectRow : function(index, preventViewNotify){
18180 if(this.locked) return;
18181 if(this.last == index){
18184 if(this.lastActive == index){
18185 this.lastActive = false;
18187 var r = this.grid.dataSource.getAt(index);
18188 this.selections.remove(r);
18189 if(!preventViewNotify){
18190 this.grid.getView().onRowDeselect(index);
18192 this.fireEvent("rowdeselect", this, index);
18193 this.fireEvent("selectionchange", this);
18197 restoreLast : function(){
18199 this.last = this._last;
18204 acceptsNav : function(row, col, cm){
18205 return !cm.isHidden(col) && cm.isCellEditable(col, row);
18209 onEditorKey : function(field, e){
18210 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18215 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18217 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18219 }else if(k == e.ENTER && !e.ctrlKey){
18223 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18225 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18227 }else if(k == e.ESC){
18231 g.startEditing(newCell[0], newCell[1]);
18236 * Ext JS Library 1.1.1
18237 * Copyright(c) 2006-2007, Ext JS, LLC.
18239 * Originally Released Under LGPL - original licence link has changed is not relivant.
18242 * <script type="text/javascript">
18246 * @class Roo.bootstrap.PagingToolbar
18248 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18250 * Create a new PagingToolbar
18251 * @param {Object} config The config object
18253 Roo.bootstrap.PagingToolbar = function(config)
18255 // old args format still supported... - xtype is prefered..
18256 // created from xtype...
18257 var ds = config.dataSource;
18258 this.toolbarItems = [];
18259 if (config.items) {
18260 this.toolbarItems = config.items;
18261 // config.items = [];
18264 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18271 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18275 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18277 * @cfg {Roo.data.Store} dataSource
18278 * The underlying data store providing the paged data
18281 * @cfg {String/HTMLElement/Element} container
18282 * container The id or element that will contain the toolbar
18285 * @cfg {Boolean} displayInfo
18286 * True to display the displayMsg (defaults to false)
18289 * @cfg {Number} pageSize
18290 * The number of records to display per page (defaults to 20)
18294 * @cfg {String} displayMsg
18295 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18297 displayMsg : 'Displaying {0} - {1} of {2}',
18299 * @cfg {String} emptyMsg
18300 * The message to display when no records are found (defaults to "No data to display")
18302 emptyMsg : 'No data to display',
18304 * Customizable piece of the default paging text (defaults to "Page")
18307 beforePageText : "Page",
18309 * Customizable piece of the default paging text (defaults to "of %0")
18312 afterPageText : "of {0}",
18314 * Customizable piece of the default paging text (defaults to "First Page")
18317 firstText : "First Page",
18319 * Customizable piece of the default paging text (defaults to "Previous Page")
18322 prevText : "Previous Page",
18324 * Customizable piece of the default paging text (defaults to "Next Page")
18327 nextText : "Next Page",
18329 * Customizable piece of the default paging text (defaults to "Last Page")
18332 lastText : "Last Page",
18334 * Customizable piece of the default paging text (defaults to "Refresh")
18337 refreshText : "Refresh",
18341 onRender : function(ct, position)
18343 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
18344 this.navgroup.parentId = this.id;
18345 this.navgroup.onRender(this.el, null);
18346 // add the buttons to the navgroup
18348 if(this.displayInfo){
18349 Roo.log(this.el.select('ul.navbar-nav',true).first());
18350 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
18351 this.displayEl = this.el.select('.x-paging-info', true).first();
18352 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
18353 // this.displayEl = navel.el.select('span',true).first();
18359 Roo.each(_this.buttons, function(e){
18360 Roo.factory(e).onRender(_this.el, null);
18364 Roo.each(_this.toolbarItems, function(e) {
18365 _this.navgroup.addItem(e);
18368 this.first = this.navgroup.addItem({
18369 tooltip: this.firstText,
18371 icon : 'fa fa-backward',
18373 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
18376 this.prev = this.navgroup.addItem({
18377 tooltip: this.prevText,
18379 icon : 'fa fa-step-backward',
18381 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
18383 //this.addSeparator();
18386 var field = this.navgroup.addItem( {
18388 cls : 'x-paging-position',
18390 html : this.beforePageText +
18391 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
18392 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
18395 this.field = field.el.select('input', true).first();
18396 this.field.on("keydown", this.onPagingKeydown, this);
18397 this.field.on("focus", function(){this.dom.select();});
18400 this.afterTextEl = field.el.select('.x-paging-after',true).first();
18401 //this.field.setHeight(18);
18402 //this.addSeparator();
18403 this.next = this.navgroup.addItem({
18404 tooltip: this.nextText,
18406 html : ' <i class="fa fa-step-forward">',
18408 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
18410 this.last = this.navgroup.addItem({
18411 tooltip: this.lastText,
18412 icon : 'fa fa-forward',
18415 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
18417 //this.addSeparator();
18418 this.loading = this.navgroup.addItem({
18419 tooltip: this.refreshText,
18420 icon: 'fa fa-refresh',
18422 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
18428 updateInfo : function(){
18429 if(this.displayEl){
18430 var count = this.ds.getCount();
18431 var msg = count == 0 ?
18435 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
18437 this.displayEl.update(msg);
18442 onLoad : function(ds, r, o){
18443 this.cursor = o.params ? o.params.start : 0;
18444 var d = this.getPageData(),
18448 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
18449 this.field.dom.value = ap;
18450 this.first.setDisabled(ap == 1);
18451 this.prev.setDisabled(ap == 1);
18452 this.next.setDisabled(ap == ps);
18453 this.last.setDisabled(ap == ps);
18454 this.loading.enable();
18459 getPageData : function(){
18460 var total = this.ds.getTotalCount();
18463 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
18464 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
18469 onLoadError : function(){
18470 this.loading.enable();
18474 onPagingKeydown : function(e){
18475 var k = e.getKey();
18476 var d = this.getPageData();
18478 var v = this.field.dom.value, pageNum;
18479 if(!v || isNaN(pageNum = parseInt(v, 10))){
18480 this.field.dom.value = d.activePage;
18483 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
18484 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
18487 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))
18489 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
18490 this.field.dom.value = pageNum;
18491 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
18494 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18496 var v = this.field.dom.value, pageNum;
18497 var increment = (e.shiftKey) ? 10 : 1;
18498 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18500 if(!v || isNaN(pageNum = parseInt(v, 10))) {
18501 this.field.dom.value = d.activePage;
18504 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
18506 this.field.dom.value = parseInt(v, 10) + increment;
18507 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
18508 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
18515 beforeLoad : function(){
18517 this.loading.disable();
18522 onClick : function(which){
18529 ds.load({params:{start: 0, limit: this.pageSize}});
18532 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
18535 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
18538 var total = ds.getTotalCount();
18539 var extra = total % this.pageSize;
18540 var lastStart = extra ? (total - extra) : total-this.pageSize;
18541 ds.load({params:{start: lastStart, limit: this.pageSize}});
18544 ds.load({params:{start: this.cursor, limit: this.pageSize}});
18550 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
18551 * @param {Roo.data.Store} store The data store to unbind
18553 unbind : function(ds){
18554 ds.un("beforeload", this.beforeLoad, this);
18555 ds.un("load", this.onLoad, this);
18556 ds.un("loadexception", this.onLoadError, this);
18557 ds.un("remove", this.updateInfo, this);
18558 ds.un("add", this.updateInfo, this);
18559 this.ds = undefined;
18563 * Binds the paging toolbar to the specified {@link Roo.data.Store}
18564 * @param {Roo.data.Store} store The data store to bind
18566 bind : function(ds){
18567 ds.on("beforeload", this.beforeLoad, this);
18568 ds.on("load", this.onLoad, this);
18569 ds.on("loadexception", this.onLoadError, this);
18570 ds.on("remove", this.updateInfo, this);
18571 ds.on("add", this.updateInfo, this);
18582 * @class Roo.bootstrap.MessageBar
18583 * @extends Roo.bootstrap.Component
18584 * Bootstrap MessageBar class
18585 * @cfg {String} html contents of the MessageBar
18586 * @cfg {String} weight (info | success | warning | danger) default info
18587 * @cfg {String} beforeClass insert the bar before the given class
18588 * @cfg {Boolean} closable (true | false) default false
18589 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
18592 * Create a new Element
18593 * @param {Object} config The config object
18596 Roo.bootstrap.MessageBar = function(config){
18597 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
18600 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
18606 beforeClass: 'bootstrap-sticky-wrap',
18608 getAutoCreate : function(){
18612 cls: 'alert alert-dismissable alert-' + this.weight,
18617 html: this.html || ''
18623 cfg.cls += ' alert-messages-fixed';
18637 onRender : function(ct, position)
18639 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
18642 var cfg = Roo.apply({}, this.getAutoCreate());
18646 cfg.cls += ' ' + this.cls;
18649 cfg.style = this.style;
18651 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
18653 this.el.setVisibilityMode(Roo.Element.DISPLAY);
18656 this.el.select('>button.close').on('click', this.hide, this);
18662 if (!this.rendered) {
18668 this.fireEvent('show', this);
18674 if (!this.rendered) {
18680 this.fireEvent('hide', this);
18683 update : function()
18685 // var e = this.el.dom.firstChild;
18687 // if(this.closable){
18688 // e = e.nextSibling;
18691 // e.data = this.html || '';
18693 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
18709 * @class Roo.bootstrap.Graph
18710 * @extends Roo.bootstrap.Component
18711 * Bootstrap Graph class
18715 @cfg {String} graphtype bar | vbar | pie
18716 @cfg {number} g_x coodinator | centre x (pie)
18717 @cfg {number} g_y coodinator | centre y (pie)
18718 @cfg {number} g_r radius (pie)
18719 @cfg {number} g_height height of the chart (respected by all elements in the set)
18720 @cfg {number} g_width width of the chart (respected by all elements in the set)
18721 @cfg {Object} title The title of the chart
18724 -opts (object) options for the chart
18726 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
18727 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
18729 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.
18730 o stacked (boolean) whether or not to tread values as in a stacked bar chart
18732 o stretch (boolean)
18734 -opts (object) options for the pie
18737 o startAngle (number)
18738 o endAngle (number)
18742 * Create a new Input
18743 * @param {Object} config The config object
18746 Roo.bootstrap.Graph = function(config){
18747 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
18753 * The img click event for the img.
18754 * @param {Roo.EventObject} e
18760 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
18771 //g_colors: this.colors,
18778 getAutoCreate : function(){
18789 onRender : function(ct,position){
18790 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
18791 this.raphael = Raphael(this.el.dom);
18793 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18794 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18795 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18796 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
18798 r.text(160, 10, "Single Series Chart").attr(txtattr);
18799 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
18800 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
18801 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
18803 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
18804 r.barchart(330, 10, 300, 220, data1);
18805 r.barchart(10, 250, 300, 220, data2, {stacked: true});
18806 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
18809 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
18810 // r.barchart(30, 30, 560, 250, xdata, {
18811 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
18812 // axis : "0 0 1 1",
18813 // axisxlabels : xdata
18814 // //yvalues : cols,
18817 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
18819 // this.load(null,xdata,{
18820 // axis : "0 0 1 1",
18821 // axisxlabels : xdata
18826 load : function(graphtype,xdata,opts){
18827 this.raphael.clear();
18829 graphtype = this.graphtype;
18834 var r = this.raphael,
18835 fin = function () {
18836 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
18838 fout = function () {
18839 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
18841 pfin = function() {
18842 this.sector.stop();
18843 this.sector.scale(1.1, 1.1, this.cx, this.cy);
18846 this.label[0].stop();
18847 this.label[0].attr({ r: 7.5 });
18848 this.label[1].attr({ "font-weight": 800 });
18851 pfout = function() {
18852 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
18855 this.label[0].animate({ r: 5 }, 500, "bounce");
18856 this.label[1].attr({ "font-weight": 400 });
18862 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
18865 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
18868 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
18869 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
18871 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
18878 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
18883 setTitle: function(o)
18888 initEvents: function() {
18891 this.el.on('click', this.onClick, this);
18895 onClick : function(e)
18897 Roo.log('img onclick');
18898 this.fireEvent('click', this, e);
18910 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
18913 * @class Roo.bootstrap.dash.NumberBox
18914 * @extends Roo.bootstrap.Component
18915 * Bootstrap NumberBox class
18916 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
18917 * @cfg {String} headline Box headline
18918 * @cfg {String} content Box content
18919 * @cfg {String} icon Box icon
18920 * @cfg {String} footer Footer text
18921 * @cfg {String} fhref Footer href
18924 * Create a new NumberBox
18925 * @param {Object} config The config object
18929 Roo.bootstrap.dash.NumberBox = function(config){
18930 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
18934 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
18944 getAutoCreate : function(){
18948 cls : 'small-box bg-' + this.bgcolor,
18956 cls : 'roo-headline',
18957 html : this.headline
18961 cls : 'roo-content',
18962 html : this.content
18976 cls : 'ion ' + this.icon
18985 cls : 'small-box-footer',
18986 href : this.fhref || '#',
18990 cfg.cn.push(footer);
18997 onRender : function(ct,position){
18998 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19005 setHeadline: function (value)
19007 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19010 setFooter: function (value, href)
19012 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19015 this.el.select('a.small-box-footer',true).first().attr('href', href);
19020 setContent: function (value)
19022 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19025 initEvents: function()
19039 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19042 * @class Roo.bootstrap.dash.TabBox
19043 * @extends Roo.bootstrap.Component
19044 * Bootstrap TabBox class
19045 * @cfg {String} title Title of the TabBox
19046 * @cfg {String} icon Icon of the TabBox
19049 * Create a new TabBox
19050 * @param {Object} config The config object
19054 Roo.bootstrap.dash.TabBox = function(config){
19055 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19059 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19064 getChildContainer : function()
19066 return this.el.select('.tab-content', true).first();
19069 getAutoCreate : function(){
19073 cls: 'pull-left header',
19081 cls: 'fa ' + this.icon
19088 cls: 'nav-tabs-custom',
19092 cls: 'nav nav-tabs pull-right',
19099 cls: 'tab-content no-padding',
19108 setTitle : function(value)
19110 this.el.select('.header', true).first().dom.innerHTML = value;
19122 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19124 * @class Roo.bootstrap.TabPane
19125 * @extends Roo.bootstrap.Component
19126 * Bootstrap TabPane class
19127 * @cfg {Boolean} active (false | true) Default false
19131 * Create a new TabPane
19132 * @param {Object} config The config object
19135 Roo.bootstrap.dash.TabPane = function(config){
19136 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19140 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
19144 // getBox : function()
19146 // return this.el.findParent('.nav-tabs-custom', false, true);
19149 getAutoCreate : function()
19157 cfg.cls += ' active';
19175 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19178 * @class Roo.bootstrap.menu.Menu
19179 * @extends Roo.bootstrap.Component
19180 * Bootstrap Menu class - container for Menu
19181 * @cfg {String} html Text of the menu
19182 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19183 * @cfg {String} icon Font awesome icon
19184 * @cfg {String} pos Menu align to (top | bottom) default bottom
19188 * Create a new Menu
19189 * @param {Object} config The config object
19193 Roo.bootstrap.menu.Menu = function(config){
19194 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19198 * @event beforeshow
19199 * Fires before this menu is displayed
19200 * @param {Roo.bootstrap.menu.Menu} this
19204 * @event beforehide
19205 * Fires before this menu is hidden
19206 * @param {Roo.bootstrap.menu.Menu} this
19211 * Fires after this menu is displayed
19212 * @param {Roo.bootstrap.menu.Menu} this
19217 * Fires after this menu is hidden
19218 * @param {Roo.bootstrap.menu.Menu} this
19223 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19224 * @param {Roo.bootstrap.menu.Menu} this
19225 * @param {Roo.EventObject} e
19232 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
19236 weight : 'default',
19241 getChildContainer : function() {
19242 if(this.isSubMenu){
19246 return this.el.select('ul.dropdown-menu', true).first();
19249 getAutoCreate : function()
19254 cls : 'roo-menu-text',
19262 cls : 'fa ' + this.icon
19273 cls : 'dropdown-button btn btn-' + this.weight,
19278 cls : 'dropdown-toggle btn btn-' + this.weight,
19288 cls : 'dropdown-menu'
19294 if(this.pos == 'top'){
19295 cfg.cls += ' dropup';
19298 if(this.isSubMenu){
19301 cls : 'dropdown-menu'
19308 onRender : function(ct, position)
19310 this.isSubMenu = ct.hasClass('dropdown-submenu');
19312 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
19315 initEvents : function()
19317 if(this.isSubMenu){
19321 this.hidden = true;
19323 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
19324 this.triggerEl.on('click', this.onTriggerPress, this);
19326 this.buttonEl = this.el.select('button.dropdown-button', true).first();
19327 this.buttonEl.on('click', this.onClick, this);
19333 if(this.isSubMenu){
19337 return this.el.select('ul.dropdown-menu', true).first();
19340 onClick : function(e)
19342 this.fireEvent("click", this, e);
19345 onTriggerPress : function(e)
19347 if (this.isVisible()) {
19354 isVisible : function(){
19355 return !this.hidden;
19360 this.fireEvent("beforeshow", this);
19362 this.hidden = false;
19363 this.el.addClass('open');
19365 Roo.get(document).on("mouseup", this.onMouseUp, this);
19367 this.fireEvent("show", this);
19374 this.fireEvent("beforehide", this);
19376 this.hidden = true;
19377 this.el.removeClass('open');
19379 Roo.get(document).un("mouseup", this.onMouseUp);
19381 this.fireEvent("hide", this);
19384 onMouseUp : function()
19398 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19401 * @class Roo.bootstrap.menu.Item
19402 * @extends Roo.bootstrap.Component
19403 * Bootstrap MenuItem class
19404 * @cfg {Boolean} submenu (true | false) default false
19405 * @cfg {String} html text of the item
19406 * @cfg {String} href the link
19407 * @cfg {Boolean} disable (true | false) default false
19408 * @cfg {Boolean} preventDefault (true | false) default true
19409 * @cfg {String} icon Font awesome icon
19410 * @cfg {String} pos Submenu align to (left | right) default right
19414 * Create a new Item
19415 * @param {Object} config The config object
19419 Roo.bootstrap.menu.Item = function(config){
19420 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
19424 * Fires when the mouse is hovering over this menu
19425 * @param {Roo.bootstrap.menu.Item} this
19426 * @param {Roo.EventObject} e
19431 * Fires when the mouse exits this menu
19432 * @param {Roo.bootstrap.menu.Item} this
19433 * @param {Roo.EventObject} e
19439 * The raw click event for the entire grid.
19440 * @param {Roo.EventObject} e
19446 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
19451 preventDefault: true,
19456 getAutoCreate : function()
19461 cls : 'roo-menu-item-text',
19469 cls : 'fa ' + this.icon
19478 href : this.href || '#',
19485 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
19489 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
19491 if(this.pos == 'left'){
19492 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
19499 initEvents : function()
19501 this.el.on('mouseover', this.onMouseOver, this);
19502 this.el.on('mouseout', this.onMouseOut, this);
19504 this.el.select('a', true).first().on('click', this.onClick, this);
19508 onClick : function(e)
19510 if(this.preventDefault){
19511 e.preventDefault();
19514 this.fireEvent("click", this, e);
19517 onMouseOver : function(e)
19519 if(this.submenu && this.pos == 'left'){
19520 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
19523 this.fireEvent("mouseover", this, e);
19526 onMouseOut : function(e)
19528 this.fireEvent("mouseout", this, e);
19540 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19543 * @class Roo.bootstrap.menu.Separator
19544 * @extends Roo.bootstrap.Component
19545 * Bootstrap Separator class
19548 * Create a new Separator
19549 * @param {Object} config The config object
19553 Roo.bootstrap.menu.Separator = function(config){
19554 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
19557 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
19559 getAutoCreate : function(){