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.
4653 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4677 RowSelection : false,
4678 CellSelection : false,
4682 getAutoCreate : function(){
4683 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4692 cfg.cls += ' table-striped';
4696 cfg.cls += ' table-hover';
4698 if (this.bordered) {
4699 cfg.cls += ' table-bordered';
4701 if (this.condensed) {
4702 cfg.cls += ' table-condensed';
4704 if (this.responsive) {
4705 cfg.cls += ' table-responsive';
4709 cfg.cls+= ' ' +this.cls;
4712 // this lot should be simplifed...
4715 cfg.align=this.align;
4718 cfg.bgcolor=this.bgcolor;
4721 cfg.border=this.border;
4723 if (this.cellpadding) {
4724 cfg.cellpadding=this.cellpadding;
4726 if (this.cellspacing) {
4727 cfg.cellspacing=this.cellspacing;
4730 cfg.frame=this.frame;
4733 cfg.rules=this.rules;
4735 if (this.sortable) {
4736 cfg.sortable=this.sortable;
4739 cfg.summary=this.summary;
4742 cfg.width=this.width;
4745 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
4748 if(this.store || this.cm){
4750 cfg.cn.push(this.renderHeader());
4753 cfg.cn.push(this.renderBody());
4756 cfg.cn.push(this.renderFooter());
4759 cfg.cls+= ' TableGrid';
4762 return { cn : [ cfg ] };
4765 initEvents : function()
4767 if(!this.store || !this.cm){
4771 Roo.log('initEvents with ds!!!!');
4775 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4776 e.on('click', _this.sort, _this);
4779 this.el.on("click", this.onClick, this);
4780 this.el.on("dblclick", this.onDblClick, this);
4782 this.parent().el.setStyle('position', 'relative');
4784 this.footer.parentId = this.id;
4785 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
4788 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
4790 this.store.on('load', this.onLoad, this);
4791 this.store.on('beforeload', this.onBeforeLoad, this);
4795 onMouseover : function(e, el)
4797 var cell = Roo.get(el);
4803 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4804 cell = cell.findParent('td', false, true);
4807 var row = cell.findParent('tr', false, true);
4808 var cellIndex = cell.dom.cellIndex;
4809 var rowIndex = row.dom.rowIndex - 1; // start from 0
4811 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
4815 onMouseout : function(e, el)
4817 var cell = Roo.get(el);
4823 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4824 cell = cell.findParent('td', false, true);
4827 var row = cell.findParent('tr', false, true);
4828 var cellIndex = cell.dom.cellIndex;
4829 var rowIndex = row.dom.rowIndex - 1; // start from 0
4831 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
4835 onClick : function(e, el)
4837 var cell = Roo.get(el);
4839 if(!cell || !this.CellSelection || !this.RowSelection){
4844 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4845 cell = cell.findParent('td', false, true);
4848 var row = cell.findParent('tr', false, true);
4849 var cellIndex = cell.dom.cellIndex;
4850 var rowIndex = row.dom.rowIndex - 1;
4852 if(this.CellSelection){
4853 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
4856 if(this.RowSelection){
4857 this.fireEvent('rowclick', this, row, rowIndex, e);
4863 onDblClick : function(e,el)
4865 var cell = Roo.get(el);
4867 if(!cell || !this.CellSelection || !this.RowSelection){
4871 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4872 cell = cell.findParent('td', false, true);
4875 var row = cell.findParent('tr', false, true);
4876 var cellIndex = cell.dom.cellIndex;
4877 var rowIndex = row.dom.rowIndex - 1;
4879 if(this.CellSelection){
4880 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
4883 if(this.RowSelection){
4884 this.fireEvent('rowdblclick', this, row, rowIndex, e);
4888 sort : function(e,el)
4890 var col = Roo.get(el)
4892 if(!col.hasClass('sortable')){
4896 var sort = col.attr('sort');
4899 if(col.hasClass('glyphicon-arrow-up')){
4903 this.store.sortInfo = {field : sort, direction : dir};
4906 Roo.log("calling footer first");
4907 this.footer.onClick('first');
4910 this.store.load({ params : { start : 0 } });
4914 renderHeader : function()
4923 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4925 var config = cm.config[i];
4930 html: cm.getColumnHeader(i)
4933 if(typeof(config.hidden) != 'undefined' && config.hidden){
4934 c.style += ' display:none;';
4937 if(typeof(config.dataIndex) != 'undefined'){
4938 c.sort = config.dataIndex;
4941 if(typeof(config.sortable) != 'undefined' && config.sortable){
4945 // if(typeof(config.align) != 'undefined' && config.align.length){
4946 // c.style += ' text-align:' + config.align + ';';
4949 if(typeof(config.width) != 'undefined'){
4950 c.style += ' width:' + config.width + 'px;';
4959 renderBody : function()
4969 colspan : this.cm.getColumnCount()
4979 renderFooter : function()
4989 colspan : this.cm.getColumnCount()
5001 Roo.log('ds onload');
5007 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5008 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5010 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5011 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5014 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5015 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5019 var tbody = this.el.select('tbody', true).first();
5023 if(this.store.getCount() > 0){
5024 this.store.data.each(function(d,rowIndex){
5030 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5031 var config = cm.config[i];
5033 var renderer = cm.getRenderer(i);
5037 if(typeof(renderer) !== 'undefined'){
5038 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5041 if(typeof(value) === 'object'){
5050 rowIndex : rowIndex,
5055 _this.fireEvent('rowclass', this, rowcfg);
5060 cls : rowcfg.rowClass,
5062 html: (typeof(value) === 'object') ? '' : value
5065 if(typeof(config.hidden) != 'undefined' && config.hidden){
5066 td.style += ' display:none;';
5069 if(typeof(config.align) != 'undefined' && config.align.length){
5070 td.style += ' text-align:' + config.align + ';';
5073 if(typeof(config.width) != 'undefined'){
5074 td.style += ' width:' + config.width + 'px;';
5082 tbody.createChild(row);
5090 Roo.each(renders, function(r){
5091 _this.renderColumn(r);
5095 Roo.each(this.el.select('tbody td', true).elements, function(e){
5096 e.on('mouseover', _this.onMouseover, _this);
5099 Roo.each(this.el.select('tbody td', true).elements, function(e){
5100 e.on('mouseout', _this.onMouseout, _this);
5103 //if(this.loadMask){
5104 // this.maskEl.hide();
5108 onBeforeLoad : function()
5110 //Roo.log('ds onBeforeLoad');
5114 //if(this.loadMask){
5115 // this.maskEl.show();
5121 this.el.select('tbody', true).first().dom.innerHTML = '';
5124 getSelectionModel : function(){
5126 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5128 return this.selModel;
5131 renderColumn : function(r)
5135 var t = r.cfg.render(r.container);
5138 Roo.each(r.cfg.cn, function(c){
5140 container: t.getChildContainer(),
5143 _this.renderColumn(child);
5160 * @class Roo.bootstrap.TableCell
5161 * @extends Roo.bootstrap.Component
5162 * Bootstrap TableCell class
5163 * @cfg {String} html cell contain text
5164 * @cfg {String} cls cell class
5165 * @cfg {String} tag cell tag (td|th) default td
5166 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5167 * @cfg {String} align Aligns the content in a cell
5168 * @cfg {String} axis Categorizes cells
5169 * @cfg {String} bgcolor Specifies the background color of a cell
5170 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5171 * @cfg {Number} colspan Specifies the number of columns a cell should span
5172 * @cfg {String} headers Specifies one or more header cells a cell is related to
5173 * @cfg {Number} height Sets the height of a cell
5174 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5175 * @cfg {Number} rowspan Sets the number of rows a cell should span
5176 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5177 * @cfg {String} valign Vertical aligns the content in a cell
5178 * @cfg {Number} width Specifies the width of a cell
5181 * Create a new TableCell
5182 * @param {Object} config The config object
5185 Roo.bootstrap.TableCell = function(config){
5186 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5189 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5209 getAutoCreate : function(){
5210 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5230 cfg.align=this.align
5236 cfg.bgcolor=this.bgcolor
5239 cfg.charoff=this.charoff
5242 cfg.colspan=this.colspan
5245 cfg.headers=this.headers
5248 cfg.height=this.height
5251 cfg.nowrap=this.nowrap
5254 cfg.rowspan=this.rowspan
5257 cfg.scope=this.scope
5260 cfg.valign=this.valign
5263 cfg.width=this.width
5282 * @class Roo.bootstrap.TableRow
5283 * @extends Roo.bootstrap.Component
5284 * Bootstrap TableRow class
5285 * @cfg {String} cls row class
5286 * @cfg {String} align Aligns the content in a table row
5287 * @cfg {String} bgcolor Specifies a background color for a table row
5288 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5289 * @cfg {String} valign Vertical aligns the content in a table row
5292 * Create a new TableRow
5293 * @param {Object} config The config object
5296 Roo.bootstrap.TableRow = function(config){
5297 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5300 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5308 getAutoCreate : function(){
5309 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5319 cfg.align = this.align;
5322 cfg.bgcolor = this.bgcolor;
5325 cfg.charoff = this.charoff;
5328 cfg.valign = this.valign;
5346 * @class Roo.bootstrap.TableBody
5347 * @extends Roo.bootstrap.Component
5348 * Bootstrap TableBody class
5349 * @cfg {String} cls element class
5350 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5351 * @cfg {String} align Aligns the content inside the element
5352 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5353 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5356 * Create a new TableBody
5357 * @param {Object} config The config object
5360 Roo.bootstrap.TableBody = function(config){
5361 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5364 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5372 getAutoCreate : function(){
5373 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5387 cfg.align = this.align;
5390 cfg.charoff = this.charoff;
5393 cfg.valign = this.valign;
5400 // initEvents : function()
5407 // this.store = Roo.factory(this.store, Roo.data);
5408 // this.store.on('load', this.onLoad, this);
5410 // this.store.load();
5414 // onLoad: function ()
5416 // this.fireEvent('load', this);
5426 * Ext JS Library 1.1.1
5427 * Copyright(c) 2006-2007, Ext JS, LLC.
5429 * Originally Released Under LGPL - original licence link has changed is not relivant.
5432 * <script type="text/javascript">
5435 // as we use this in bootstrap.
5436 Roo.namespace('Roo.form');
5438 * @class Roo.form.Action
5439 * Internal Class used to handle form actions
5441 * @param {Roo.form.BasicForm} el The form element or its id
5442 * @param {Object} config Configuration options
5447 // define the action interface
5448 Roo.form.Action = function(form, options){
5450 this.options = options || {};
5453 * Client Validation Failed
5456 Roo.form.Action.CLIENT_INVALID = 'client';
5458 * Server Validation Failed
5461 Roo.form.Action.SERVER_INVALID = 'server';
5463 * Connect to Server Failed
5466 Roo.form.Action.CONNECT_FAILURE = 'connect';
5468 * Reading Data from Server Failed
5471 Roo.form.Action.LOAD_FAILURE = 'load';
5473 Roo.form.Action.prototype = {
5475 failureType : undefined,
5476 response : undefined,
5480 run : function(options){
5485 success : function(response){
5490 handleResponse : function(response){
5494 // default connection failure
5495 failure : function(response){
5497 this.response = response;
5498 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5499 this.form.afterAction(this, false);
5502 processResponse : function(response){
5503 this.response = response;
5504 if(!response.responseText){
5507 this.result = this.handleResponse(response);
5511 // utility functions used internally
5512 getUrl : function(appendParams){
5513 var url = this.options.url || this.form.url || this.form.el.dom.action;
5515 var p = this.getParams();
5517 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5523 getMethod : function(){
5524 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5527 getParams : function(){
5528 var bp = this.form.baseParams;
5529 var p = this.options.params;
5531 if(typeof p == "object"){
5532 p = Roo.urlEncode(Roo.applyIf(p, bp));
5533 }else if(typeof p == 'string' && bp){
5534 p += '&' + Roo.urlEncode(bp);
5537 p = Roo.urlEncode(bp);
5542 createCallback : function(){
5544 success: this.success,
5545 failure: this.failure,
5547 timeout: (this.form.timeout*1000),
5548 upload: this.form.fileUpload ? this.success : undefined
5553 Roo.form.Action.Submit = function(form, options){
5554 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
5557 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
5560 haveProgress : false,
5561 uploadComplete : false,
5563 // uploadProgress indicator.
5564 uploadProgress : function()
5566 if (!this.form.progressUrl) {
5570 if (!this.haveProgress) {
5571 Roo.MessageBox.progress("Uploading", "Uploading");
5573 if (this.uploadComplete) {
5574 Roo.MessageBox.hide();
5578 this.haveProgress = true;
5580 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
5582 var c = new Roo.data.Connection();
5584 url : this.form.progressUrl,
5589 success : function(req){
5590 //console.log(data);
5594 rdata = Roo.decode(req.responseText)
5596 Roo.log("Invalid data from server..");
5600 if (!rdata || !rdata.success) {
5602 Roo.MessageBox.alert(Roo.encode(rdata));
5605 var data = rdata.data;
5607 if (this.uploadComplete) {
5608 Roo.MessageBox.hide();
5613 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
5614 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
5617 this.uploadProgress.defer(2000,this);
5620 failure: function(data) {
5621 Roo.log('progress url failed ');
5632 // run get Values on the form, so it syncs any secondary forms.
5633 this.form.getValues();
5635 var o = this.options;
5636 var method = this.getMethod();
5637 var isPost = method == 'POST';
5638 if(o.clientValidation === false || this.form.isValid()){
5640 if (this.form.progressUrl) {
5641 this.form.findField('UPLOAD_IDENTIFIER').setValue(
5642 (new Date() * 1) + '' + Math.random());
5647 Roo.Ajax.request(Roo.apply(this.createCallback(), {
5648 form:this.form.el.dom,
5649 url:this.getUrl(!isPost),
5651 params:isPost ? this.getParams() : null,
5652 isUpload: this.form.fileUpload
5655 this.uploadProgress();
5657 }else if (o.clientValidation !== false){ // client validation failed
5658 this.failureType = Roo.form.Action.CLIENT_INVALID;
5659 this.form.afterAction(this, false);
5663 success : function(response)
5665 this.uploadComplete= true;
5666 if (this.haveProgress) {
5667 Roo.MessageBox.hide();
5671 var result = this.processResponse(response);
5672 if(result === true || result.success){
5673 this.form.afterAction(this, true);
5677 this.form.markInvalid(result.errors);
5678 this.failureType = Roo.form.Action.SERVER_INVALID;
5680 this.form.afterAction(this, false);
5682 failure : function(response)
5684 this.uploadComplete= true;
5685 if (this.haveProgress) {
5686 Roo.MessageBox.hide();
5689 this.response = response;
5690 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5691 this.form.afterAction(this, false);
5694 handleResponse : function(response){
5695 if(this.form.errorReader){
5696 var rs = this.form.errorReader.read(response);
5699 for(var i = 0, len = rs.records.length; i < len; i++) {
5700 var r = rs.records[i];
5704 if(errors.length < 1){
5708 success : rs.success,
5714 ret = Roo.decode(response.responseText);
5718 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
5728 Roo.form.Action.Load = function(form, options){
5729 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
5730 this.reader = this.form.reader;
5733 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
5738 Roo.Ajax.request(Roo.apply(
5739 this.createCallback(), {
5740 method:this.getMethod(),
5741 url:this.getUrl(false),
5742 params:this.getParams()
5746 success : function(response){
5748 var result = this.processResponse(response);
5749 if(result === true || !result.success || !result.data){
5750 this.failureType = Roo.form.Action.LOAD_FAILURE;
5751 this.form.afterAction(this, false);
5754 this.form.clearInvalid();
5755 this.form.setValues(result.data);
5756 this.form.afterAction(this, true);
5759 handleResponse : function(response){
5760 if(this.form.reader){
5761 var rs = this.form.reader.read(response);
5762 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
5764 success : rs.success,
5768 return Roo.decode(response.responseText);
5772 Roo.form.Action.ACTION_TYPES = {
5773 'load' : Roo.form.Action.Load,
5774 'submit' : Roo.form.Action.Submit
5783 * @class Roo.bootstrap.Form
5784 * @extends Roo.bootstrap.Component
5785 * Bootstrap Form class
5786 * @cfg {String} method GET | POST (default POST)
5787 * @cfg {String} labelAlign top | left (default top)
5788 * @cfg {String} align left | right - for navbars
5793 * @param {Object} config The config object
5797 Roo.bootstrap.Form = function(config){
5798 Roo.bootstrap.Form.superclass.constructor.call(this, config);
5801 * @event clientvalidation
5802 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
5803 * @param {Form} this
5804 * @param {Boolean} valid true if the form has passed client-side validation
5806 clientvalidation: true,
5808 * @event beforeaction
5809 * Fires before any action is performed. Return false to cancel the action.
5810 * @param {Form} this
5811 * @param {Action} action The action to be performed
5815 * @event actionfailed
5816 * Fires when an action fails.
5817 * @param {Form} this
5818 * @param {Action} action The action that failed
5820 actionfailed : true,
5822 * @event actioncomplete
5823 * Fires when an action is completed.
5824 * @param {Form} this
5825 * @param {Action} action The action that completed
5827 actioncomplete : true
5832 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
5835 * @cfg {String} method
5836 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
5841 * The URL to use for form actions if one isn't supplied in the action options.
5844 * @cfg {Boolean} fileUpload
5845 * Set to true if this form is a file upload.
5849 * @cfg {Object} baseParams
5850 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
5854 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
5858 * @cfg {Sting} align (left|right) for navbar forms
5863 activeAction : null,
5866 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5867 * element by passing it or its id or mask the form itself by passing in true.
5870 waitMsgTarget : false,
5875 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5876 * element by passing it or its id or mask the form itself by passing in true.
5880 getAutoCreate : function(){
5884 method : this.method || 'POST',
5885 id : this.id || Roo.id(),
5888 if (this.parent().xtype.match(/^Nav/)) {
5889 cfg.cls = 'navbar-form navbar-' + this.align;
5893 if (this.labelAlign == 'left' ) {
5894 cfg.cls += ' form-horizontal';
5900 initEvents : function()
5902 this.el.on('submit', this.onSubmit, this);
5903 // this was added as random key presses on the form where triggering form submit.
5904 this.el.on('keypress', function(e) {
5905 if (e.getCharCode() != 13) {
5908 // we might need to allow it for textareas.. and some other items.
5909 // check e.getTarget().
5911 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
5915 Roo.log("keypress blocked");
5923 onSubmit : function(e){
5928 * Returns true if client-side validation on the form is successful.
5931 isValid : function(){
5932 var items = this.getItems();
5934 items.each(function(f){
5943 * Returns true if any fields in this form have changed since their original load.
5946 isDirty : function(){
5948 var items = this.getItems();
5949 items.each(function(f){
5959 * Performs a predefined action (submit or load) or custom actions you define on this form.
5960 * @param {String} actionName The name of the action type
5961 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
5962 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
5963 * accept other config options):
5965 Property Type Description
5966 ---------------- --------------- ----------------------------------------------------------------------------------
5967 url String The url for the action (defaults to the form's url)
5968 method String The form method to use (defaults to the form's method, or POST if not defined)
5969 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
5970 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
5971 validate the form on the client (defaults to false)
5973 * @return {BasicForm} this
5975 doAction : function(action, options){
5976 if(typeof action == 'string'){
5977 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
5979 if(this.fireEvent('beforeaction', this, action) !== false){
5980 this.beforeAction(action);
5981 action.run.defer(100, action);
5987 beforeAction : function(action){
5988 var o = action.options;
5990 // not really supported yet.. ??
5992 //if(this.waitMsgTarget === true){
5993 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
5994 //}else if(this.waitMsgTarget){
5995 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
5996 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
5998 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6004 afterAction : function(action, success){
6005 this.activeAction = null;
6006 var o = action.options;
6008 //if(this.waitMsgTarget === true){
6010 //}else if(this.waitMsgTarget){
6011 // this.waitMsgTarget.unmask();
6013 // Roo.MessageBox.updateProgress(1);
6014 // Roo.MessageBox.hide();
6021 Roo.callback(o.success, o.scope, [this, action]);
6022 this.fireEvent('actioncomplete', this, action);
6026 // failure condition..
6027 // we have a scenario where updates need confirming.
6028 // eg. if a locking scenario exists..
6029 // we look for { errors : { needs_confirm : true }} in the response.
6031 (typeof(action.result) != 'undefined') &&
6032 (typeof(action.result.errors) != 'undefined') &&
6033 (typeof(action.result.errors.needs_confirm) != 'undefined')
6036 Roo.log("not supported yet");
6039 Roo.MessageBox.confirm(
6040 "Change requires confirmation",
6041 action.result.errorMsg,
6046 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6056 Roo.callback(o.failure, o.scope, [this, action]);
6057 // show an error message if no failed handler is set..
6058 if (!this.hasListener('actionfailed')) {
6059 Roo.log("need to add dialog support");
6061 Roo.MessageBox.alert("Error",
6062 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6063 action.result.errorMsg :
6064 "Saving Failed, please check your entries or try again"
6069 this.fireEvent('actionfailed', this, action);
6074 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6075 * @param {String} id The value to search for
6078 findField : function(id){
6079 var items = this.getItems();
6080 var field = items.get(id);
6082 items.each(function(f){
6083 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6090 return field || null;
6093 * Mark fields in this form invalid in bulk.
6094 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6095 * @return {BasicForm} this
6097 markInvalid : function(errors){
6098 if(errors instanceof Array){
6099 for(var i = 0, len = errors.length; i < len; i++){
6100 var fieldError = errors[i];
6101 var f = this.findField(fieldError.id);
6103 f.markInvalid(fieldError.msg);
6109 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6110 field.markInvalid(errors[id]);
6114 //Roo.each(this.childForms || [], function (f) {
6115 // f.markInvalid(errors);
6122 * Set values for fields in this form in bulk.
6123 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6124 * @return {BasicForm} this
6126 setValues : function(values){
6127 if(values instanceof Array){ // array of objects
6128 for(var i = 0, len = values.length; i < len; i++){
6130 var f = this.findField(v.id);
6132 f.setValue(v.value);
6133 if(this.trackResetOnLoad){
6134 f.originalValue = f.getValue();
6138 }else{ // object hash
6141 if(typeof values[id] != 'function' && (field = this.findField(id))){
6143 if (field.setFromData &&
6145 field.displayField &&
6146 // combos' with local stores can
6147 // be queried via setValue()
6148 // to set their value..
6149 (field.store && !field.store.isLocal)
6153 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6154 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6155 field.setFromData(sd);
6158 field.setValue(values[id]);
6162 if(this.trackResetOnLoad){
6163 field.originalValue = field.getValue();
6169 //Roo.each(this.childForms || [], function (f) {
6170 // f.setValues(values);
6177 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6178 * they are returned as an array.
6179 * @param {Boolean} asString
6182 getValues : function(asString){
6183 //if (this.childForms) {
6184 // copy values from the child forms
6185 // Roo.each(this.childForms, function (f) {
6186 // this.setValues(f.getValues());
6192 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6193 if(asString === true){
6196 return Roo.urlDecode(fs);
6200 * Returns the fields in this form as an object with key/value pairs.
6201 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6204 getFieldValues : function(with_hidden)
6206 var items = this.getItems();
6208 items.each(function(f){
6212 var v = f.getValue();
6213 if (f.inputType =='radio') {
6214 if (typeof(ret[f.getName()]) == 'undefined') {
6215 ret[f.getName()] = ''; // empty..
6218 if (!f.el.dom.checked) {
6226 // not sure if this supported any more..
6227 if ((typeof(v) == 'object') && f.getRawValue) {
6228 v = f.getRawValue() ; // dates..
6230 // combo boxes where name != hiddenName...
6231 if (f.name != f.getName()) {
6232 ret[f.name] = f.getRawValue();
6234 ret[f.getName()] = v;
6241 * Clears all invalid messages in this form.
6242 * @return {BasicForm} this
6244 clearInvalid : function(){
6245 var items = this.getItems();
6247 items.each(function(f){
6258 * @return {BasicForm} this
6261 var items = this.getItems();
6262 items.each(function(f){
6266 Roo.each(this.childForms || [], function (f) {
6273 getItems : function()
6275 var r=new Roo.util.MixedCollection(false, function(o){
6276 return o.id || (o.id = Roo.id());
6278 var iter = function(el) {
6285 Roo.each(el.items,function(e) {
6304 * Ext JS Library 1.1.1
6305 * Copyright(c) 2006-2007, Ext JS, LLC.
6307 * Originally Released Under LGPL - original licence link has changed is not relivant.
6310 * <script type="text/javascript">
6313 * @class Roo.form.VTypes
6314 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6317 Roo.form.VTypes = function(){
6318 // closure these in so they are only created once.
6319 var alpha = /^[a-zA-Z_]+$/;
6320 var alphanum = /^[a-zA-Z0-9_]+$/;
6321 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6322 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6324 // All these messages and functions are configurable
6327 * The function used to validate email addresses
6328 * @param {String} value The email address
6330 'email' : function(v){
6331 return email.test(v);
6334 * The error text to display when the email validation function returns false
6337 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6339 * The keystroke filter mask to be applied on email input
6342 'emailMask' : /[a-z0-9_\.\-@]/i,
6345 * The function used to validate URLs
6346 * @param {String} value The URL
6348 'url' : function(v){
6352 * The error text to display when the url validation function returns false
6355 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6358 * The function used to validate alpha values
6359 * @param {String} value The value
6361 'alpha' : function(v){
6362 return alpha.test(v);
6365 * The error text to display when the alpha validation function returns false
6368 'alphaText' : 'This field should only contain letters and _',
6370 * The keystroke filter mask to be applied on alpha input
6373 'alphaMask' : /[a-z_]/i,
6376 * The function used to validate alphanumeric values
6377 * @param {String} value The value
6379 'alphanum' : function(v){
6380 return alphanum.test(v);
6383 * The error text to display when the alphanumeric validation function returns false
6386 'alphanumText' : 'This field should only contain letters, numbers and _',
6388 * The keystroke filter mask to be applied on alphanumeric input
6391 'alphanumMask' : /[a-z0-9_]/i
6401 * @class Roo.bootstrap.Input
6402 * @extends Roo.bootstrap.Component
6403 * Bootstrap Input class
6404 * @cfg {Boolean} disabled is it disabled
6405 * @cfg {String} fieldLabel - the label associated
6406 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6407 * @cfg {String} name name of the input
6408 * @cfg {string} fieldLabel - the label associated
6409 * @cfg {string} inputType - input / file submit ...
6410 * @cfg {string} placeholder - placeholder to put in text.
6411 * @cfg {string} before - input group add on before
6412 * @cfg {string} after - input group add on after
6413 * @cfg {string} size - (lg|sm) or leave empty..
6414 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6415 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6416 * @cfg {Number} md colspan out of 12 for computer-sized screens
6417 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6418 * @cfg {string} value default value of the input
6419 * @cfg {Number} labelWidth set the width of label (0-12)
6420 * @cfg {String} labelAlign (top|left)
6421 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6422 * @cfg {String} align (left|center|right) Default left
6423 * @cfg {Boolean} formatedValue (true | false) Default false
6427 * Create a new Input
6428 * @param {Object} config The config object
6431 Roo.bootstrap.Input = function(config){
6432 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6437 * Fires when this field receives input focus.
6438 * @param {Roo.form.Field} this
6443 * Fires when this field loses input focus.
6444 * @param {Roo.form.Field} this
6449 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6450 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6451 * @param {Roo.form.Field} this
6452 * @param {Roo.EventObject} e The event object
6457 * Fires just before the field blurs if the field value has changed.
6458 * @param {Roo.form.Field} this
6459 * @param {Mixed} newValue The new value
6460 * @param {Mixed} oldValue The original value
6465 * Fires after the field has been marked as invalid.
6466 * @param {Roo.form.Field} this
6467 * @param {String} msg The validation message
6472 * Fires after the field has been validated with no errors.
6473 * @param {Roo.form.Field} this
6478 * Fires after the key up
6479 * @param {Roo.form.Field} this
6480 * @param {Roo.EventObject} e The event Object
6484 * @event formatedValue
6485 * Fires when get the value of the formated input
6486 * @param {Roo.bootstrap.Input} this
6487 * @param {String} value
6489 formatedValue : true
6493 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6495 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6496 automatic validation (defaults to "keyup").
6498 validationEvent : "keyup",
6500 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6502 validateOnBlur : true,
6504 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6506 validationDelay : 250,
6508 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6510 focusClass : "x-form-focus", // not needed???
6514 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6516 invalidClass : "has-error",
6519 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6521 selectOnFocus : false,
6524 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6528 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6533 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6535 disableKeyFilter : false,
6538 * @cfg {Boolean} disabled True to disable the field (defaults to false).
6542 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6546 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6548 blankText : "This field is required",
6551 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
6555 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
6557 maxLength : Number.MAX_VALUE,
6559 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
6561 minLengthText : "The minimum length for this field is {0}",
6563 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
6565 maxLengthText : "The maximum length for this field is {0}",
6569 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
6570 * If available, this function will be called only after the basic validators all return true, and will be passed the
6571 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
6575 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
6576 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
6577 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
6581 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
6604 formatedValue : false,
6606 parentLabelAlign : function()
6609 while (parent.parent()) {
6610 parent = parent.parent();
6611 if (typeof(parent.labelAlign) !='undefined') {
6612 return parent.labelAlign;
6619 getAutoCreate : function(){
6621 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6627 if(this.inputType != 'hidden'){
6628 cfg.cls = 'form-group' //input-group
6634 type : this.inputType,
6636 cls : 'form-control',
6637 placeholder : this.placeholder || ''
6642 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
6645 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6646 input.maxLength = this.maxLength;
6649 if (this.disabled) {
6650 input.disabled=true;
6653 if (this.readOnly) {
6654 input.readonly=true;
6658 input.name = this.name;
6661 input.cls += ' input-' + this.size;
6664 ['xs','sm','md','lg'].map(function(size){
6665 if (settings[size]) {
6666 cfg.cls += ' col-' + size + '-' + settings[size];
6670 var inputblock = input;
6672 if (this.before || this.after) {
6675 cls : 'input-group',
6678 if (this.before && typeof(this.before) == 'string') {
6680 inputblock.cn.push({
6682 cls : 'roo-input-before input-group-addon',
6686 if (this.before && typeof(this.before) == 'object') {
6687 this.before = Roo.factory(this.before);
6688 Roo.log(this.before);
6689 inputblock.cn.push({
6691 cls : 'roo-input-before input-group-' +
6692 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6696 inputblock.cn.push(input);
6698 if (this.after && typeof(this.after) == 'string') {
6699 inputblock.cn.push({
6701 cls : 'roo-input-after input-group-addon',
6705 if (this.after && typeof(this.after) == 'object') {
6706 this.after = Roo.factory(this.after);
6707 Roo.log(this.after);
6708 inputblock.cn.push({
6710 cls : 'roo-input-after input-group-' +
6711 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6716 if (align ==='left' && this.fieldLabel.length) {
6717 Roo.log("left and has label");
6723 cls : 'control-label col-sm-' + this.labelWidth,
6724 html : this.fieldLabel
6728 cls : "col-sm-" + (12 - this.labelWidth),
6735 } else if ( this.fieldLabel.length) {
6741 //cls : 'input-group-addon',
6742 html : this.fieldLabel
6752 Roo.log(" no label && no align");
6761 Roo.log('input-parentType: ' + this.parentType);
6763 if (this.parentType === 'Navbar' && this.parent().bar) {
6764 cfg.cls += ' navbar-form';
6772 * return the real input element.
6774 inputEl: function ()
6776 return this.el.select('input.form-control',true).first();
6778 setDisabled : function(v)
6780 var i = this.inputEl().dom;
6782 i.removeAttribute('disabled');
6786 i.setAttribute('disabled','true');
6788 initEvents : function()
6791 this.inputEl().on("keydown" , this.fireKey, this);
6792 this.inputEl().on("focus", this.onFocus, this);
6793 this.inputEl().on("blur", this.onBlur, this);
6795 this.inputEl().relayEvent('keyup', this);
6797 // reference to original value for reset
6798 this.originalValue = this.getValue();
6799 //Roo.form.TextField.superclass.initEvents.call(this);
6800 if(this.validationEvent == 'keyup'){
6801 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
6802 this.inputEl().on('keyup', this.filterValidation, this);
6804 else if(this.validationEvent !== false){
6805 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
6808 if(this.selectOnFocus){
6809 this.on("focus", this.preFocus, this);
6812 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
6813 this.inputEl().on("keypress", this.filterKeys, this);
6816 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
6817 this.el.on("click", this.autoSize, this);
6820 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
6821 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
6824 if (typeof(this.before) == 'object') {
6825 this.before.render(this.el.select('.roo-input-before',true).first());
6827 if (typeof(this.after) == 'object') {
6828 this.after.render(this.el.select('.roo-input-after',true).first());
6833 filterValidation : function(e){
6834 if(!e.isNavKeyPress()){
6835 this.validationTask.delay(this.validationDelay);
6839 * Validates the field value
6840 * @return {Boolean} True if the value is valid, else false
6842 validate : function(){
6843 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
6844 if(this.disabled || this.validateValue(this.getRawValue())){
6845 this.clearInvalid();
6853 * Validates a value according to the field's validation rules and marks the field as invalid
6854 * if the validation fails
6855 * @param {Mixed} value The value to validate
6856 * @return {Boolean} True if the value is valid, else false
6858 validateValue : function(value){
6859 if(value.length < 1) { // if it's blank
6860 if(this.allowBlank){
6861 this.clearInvalid();
6864 this.markInvalid(this.blankText);
6868 if(value.length < this.minLength){
6869 this.markInvalid(String.format(this.minLengthText, this.minLength));
6872 if(value.length > this.maxLength){
6873 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
6877 var vt = Roo.form.VTypes;
6878 if(!vt[this.vtype](value, this)){
6879 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
6883 if(typeof this.validator == "function"){
6884 var msg = this.validator(value);
6886 this.markInvalid(msg);
6890 if(this.regex && !this.regex.test(value)){
6891 this.markInvalid(this.regexText);
6900 fireKey : function(e){
6901 //Roo.log('field ' + e.getKey());
6902 if(e.isNavKeyPress()){
6903 this.fireEvent("specialkey", this, e);
6906 focus : function (selectText){
6908 this.inputEl().focus();
6909 if(selectText === true){
6910 this.inputEl().dom.select();
6916 onFocus : function(){
6917 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6918 // this.el.addClass(this.focusClass);
6921 this.hasFocus = true;
6922 this.startValue = this.getValue();
6923 this.fireEvent("focus", this);
6927 beforeBlur : Roo.emptyFn,
6931 onBlur : function(){
6933 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6934 //this.el.removeClass(this.focusClass);
6936 this.hasFocus = false;
6937 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
6940 var v = this.getValue();
6941 if(String(v) !== String(this.startValue)){
6942 this.fireEvent('change', this, v, this.startValue);
6944 this.fireEvent("blur", this);
6948 * Resets the current field value to the originally loaded value and clears any validation messages
6951 this.setValue(this.originalValue);
6952 this.clearInvalid();
6955 * Returns the name of the field
6956 * @return {Mixed} name The name field
6958 getName: function(){
6962 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
6963 * @return {Mixed} value The field value
6965 getValue : function(){
6967 var v = this.inputEl().getValue();
6969 if(this.formatedValue){
6971 this.fireEvent("formatedValue", this, v);
6979 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
6980 * @return {Mixed} value The field value
6982 getRawValue : function(){
6983 var v = this.inputEl().getValue();
6989 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
6990 * @param {Mixed} value The value to set
6992 setRawValue : function(v){
6993 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6996 selectText : function(start, end){
6997 var v = this.getRawValue();
6999 start = start === undefined ? 0 : start;
7000 end = end === undefined ? v.length : end;
7001 var d = this.inputEl().dom;
7002 if(d.setSelectionRange){
7003 d.setSelectionRange(start, end);
7004 }else if(d.createTextRange){
7005 var range = d.createTextRange();
7006 range.moveStart("character", start);
7007 range.moveEnd("character", v.length-end);
7014 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7015 * @param {Mixed} value The value to set
7017 setValue : function(v){
7020 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7026 processValue : function(value){
7027 if(this.stripCharsRe){
7028 var newValue = value.replace(this.stripCharsRe, '');
7029 if(newValue !== value){
7030 this.setRawValue(newValue);
7037 preFocus : function(){
7039 if(this.selectOnFocus){
7040 this.inputEl().dom.select();
7043 filterKeys : function(e){
7045 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7048 var c = e.getCharCode(), cc = String.fromCharCode(c);
7049 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7052 if(!this.maskRe.test(cc)){
7057 * Clear any invalid styles/messages for this field
7059 clearInvalid : function(){
7061 if(!this.el || this.preventMark){ // not rendered
7064 this.el.removeClass(this.invalidClass);
7066 switch(this.msgTarget){
7068 this.el.dom.qtip = '';
7071 this.el.dom.title = '';
7075 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7080 this.errorIcon.dom.qtip = '';
7081 this.errorIcon.hide();
7082 this.un('resize', this.alignErrorIcon, this);
7086 var t = Roo.getDom(this.msgTarget);
7088 t.style.display = 'none';
7092 this.fireEvent('valid', this);
7095 * Mark this field as invalid
7096 * @param {String} msg The validation message
7098 markInvalid : function(msg){
7099 if(!this.el || this.preventMark){ // not rendered
7102 this.el.addClass(this.invalidClass);
7104 msg = msg || this.invalidText;
7105 switch(this.msgTarget){
7107 this.el.dom.qtip = msg;
7108 this.el.dom.qclass = 'x-form-invalid-tip';
7109 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7110 Roo.QuickTips.enable();
7114 this.el.dom.title = msg;
7118 var elp = this.el.findParent('.x-form-element', 5, true);
7119 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7120 this.errorEl.setWidth(elp.getWidth(true)-20);
7122 this.errorEl.update(msg);
7123 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7126 if(!this.errorIcon){
7127 var elp = this.el.findParent('.x-form-element', 5, true);
7128 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7130 this.alignErrorIcon();
7131 this.errorIcon.dom.qtip = msg;
7132 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7133 this.errorIcon.show();
7134 this.on('resize', this.alignErrorIcon, this);
7137 var t = Roo.getDom(this.msgTarget);
7139 t.style.display = this.msgDisplay;
7143 this.fireEvent('invalid', this, msg);
7146 SafariOnKeyDown : function(event)
7148 // this is a workaround for a password hang bug on chrome/ webkit.
7150 var isSelectAll = false;
7152 if(this.inputEl().dom.selectionEnd > 0){
7153 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7155 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7156 event.preventDefault();
7161 if(isSelectAll){ // backspace and delete key
7163 event.preventDefault();
7164 // this is very hacky as keydown always get's upper case.
7166 var cc = String.fromCharCode(event.getCharCode());
7167 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7171 adjustWidth : function(tag, w){
7172 tag = tag.toLowerCase();
7173 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7174 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7178 if(tag == 'textarea'){
7181 }else if(Roo.isOpera){
7185 if(tag == 'textarea'){
7204 * @class Roo.bootstrap.TextArea
7205 * @extends Roo.bootstrap.Input
7206 * Bootstrap TextArea class
7207 * @cfg {Number} cols Specifies the visible width of a text area
7208 * @cfg {Number} rows Specifies the visible number of lines in a text area
7209 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7210 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7211 * @cfg {string} html text
7214 * Create a new TextArea
7215 * @param {Object} config The config object
7218 Roo.bootstrap.TextArea = function(config){
7219 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7223 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7233 getAutoCreate : function(){
7235 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7246 value : this.value || '',
7247 html: this.html || '',
7248 cls : 'form-control',
7249 placeholder : this.placeholder || ''
7253 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7254 input.maxLength = this.maxLength;
7258 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7262 input.cols = this.cols;
7265 if (this.readOnly) {
7266 input.readonly = true;
7270 input.name = this.name;
7274 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7278 ['xs','sm','md','lg'].map(function(size){
7279 if (settings[size]) {
7280 cfg.cls += ' col-' + size + '-' + settings[size];
7284 var inputblock = input;
7286 if (this.before || this.after) {
7289 cls : 'input-group',
7293 inputblock.cn.push({
7295 cls : 'input-group-addon',
7299 inputblock.cn.push(input);
7301 inputblock.cn.push({
7303 cls : 'input-group-addon',
7310 if (align ==='left' && this.fieldLabel.length) {
7311 Roo.log("left and has label");
7317 cls : 'control-label col-sm-' + this.labelWidth,
7318 html : this.fieldLabel
7322 cls : "col-sm-" + (12 - this.labelWidth),
7329 } else if ( this.fieldLabel.length) {
7335 //cls : 'input-group-addon',
7336 html : this.fieldLabel
7346 Roo.log(" no label && no align");
7356 if (this.disabled) {
7357 input.disabled=true;
7364 * return the real textarea element.
7366 inputEl: function ()
7368 return this.el.select('textarea.form-control',true).first();
7376 * trigger field - base class for combo..
7381 * @class Roo.bootstrap.TriggerField
7382 * @extends Roo.bootstrap.Input
7383 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7384 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7385 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7386 * for which you can provide a custom implementation. For example:
7388 var trigger = new Roo.bootstrap.TriggerField();
7389 trigger.onTriggerClick = myTriggerFn;
7390 trigger.applyTo('my-field');
7393 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7394 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7395 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7396 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7398 * Create a new TriggerField.
7399 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7400 * to the base TextField)
7402 Roo.bootstrap.TriggerField = function(config){
7403 this.mimicing = false;
7404 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7407 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7409 * @cfg {String} triggerClass A CSS class to apply to the trigger
7412 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7416 /** @cfg {Boolean} grow @hide */
7417 /** @cfg {Number} growMin @hide */
7418 /** @cfg {Number} growMax @hide */
7424 autoSize: Roo.emptyFn,
7431 actionMode : 'wrap',
7435 getAutoCreate : function(){
7437 var parent = this.parent();
7439 var align = this.labelAlign || this.parentLabelAlign();
7444 cls: 'form-group' //input-group
7451 type : this.inputType,
7452 cls : 'form-control',
7453 autocomplete: 'off',
7454 placeholder : this.placeholder || ''
7458 input.name = this.name;
7461 input.cls += ' input-' + this.size;
7464 if (this.disabled) {
7465 input.disabled=true;
7468 var inputblock = input;
7470 if (this.before || this.after) {
7473 cls : 'input-group',
7477 inputblock.cn.push({
7479 cls : 'input-group-addon',
7483 inputblock.cn.push(input);
7485 inputblock.cn.push({
7487 cls : 'input-group-addon',
7500 cls: 'form-hidden-field'
7508 Roo.log('multiple');
7516 cls: 'form-hidden-field'
7520 cls: 'select2-choices',
7524 cls: 'select2-search-field',
7537 cls: 'select2-container input-group',
7542 cls: 'typeahead typeahead-long dropdown-menu',
7543 style: 'display:none'
7551 cls : 'input-group-addon btn dropdown-toggle',
7559 cls: 'combobox-clear',
7573 combobox.cls += ' select2-container-multi';
7576 if (align ==='left' && this.fieldLabel.length) {
7578 Roo.log("left and has label");
7584 cls : 'control-label col-sm-' + this.labelWidth,
7585 html : this.fieldLabel
7589 cls : "col-sm-" + (12 - this.labelWidth),
7596 } else if ( this.fieldLabel.length) {
7602 //cls : 'input-group-addon',
7603 html : this.fieldLabel
7613 Roo.log(" no label && no align");
7620 ['xs','sm','md','lg'].map(function(size){
7621 if (settings[size]) {
7622 cfg.cls += ' col-' + size + '-' + settings[size];
7633 onResize : function(w, h){
7634 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
7635 // if(typeof w == 'number'){
7636 // var x = w - this.trigger.getWidth();
7637 // this.inputEl().setWidth(this.adjustWidth('input', x));
7638 // this.trigger.setStyle('left', x+'px');
7643 adjustSize : Roo.BoxComponent.prototype.adjustSize,
7646 getResizeEl : function(){
7647 return this.inputEl();
7651 getPositionEl : function(){
7652 return this.inputEl();
7656 alignErrorIcon : function(){
7657 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
7661 initEvents : function(){
7663 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
7664 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
7666 this.trigger = this.el.select('span.dropdown-toggle',true).first();
7667 if(this.hideTrigger){
7668 this.trigger.setDisplayed(false);
7670 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
7674 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
7677 //this.trigger.addClassOnOver('x-form-trigger-over');
7678 //this.trigger.addClassOnClick('x-form-trigger-click');
7681 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
7686 initTrigger : function(){
7691 onDestroy : function(){
7693 this.trigger.removeAllListeners();
7694 // this.trigger.remove();
7697 // this.wrap.remove();
7699 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
7703 onFocus : function(){
7704 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
7707 this.wrap.addClass('x-trigger-wrap-focus');
7708 this.mimicing = true;
7709 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
7710 if(this.monitorTab){
7711 this.el.on("keydown", this.checkTab, this);
7718 checkTab : function(e){
7719 if(e.getKey() == e.TAB){
7725 onBlur : function(){
7730 mimicBlur : function(e, t){
7732 if(!this.wrap.contains(t) && this.validateBlur()){
7739 triggerBlur : function(){
7740 this.mimicing = false;
7741 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
7742 if(this.monitorTab){
7743 this.el.un("keydown", this.checkTab, this);
7745 //this.wrap.removeClass('x-trigger-wrap-focus');
7746 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
7750 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
7751 validateBlur : function(e, t){
7756 onDisable : function(){
7757 this.inputEl().dom.disabled = true;
7758 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
7760 // this.wrap.addClass('x-item-disabled');
7765 onEnable : function(){
7766 this.inputEl().dom.disabled = false;
7767 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
7769 // this.el.removeClass('x-item-disabled');
7774 onShow : function(){
7775 var ae = this.getActionEl();
7778 ae.dom.style.display = '';
7779 ae.dom.style.visibility = 'visible';
7785 onHide : function(){
7786 var ae = this.getActionEl();
7787 ae.dom.style.display = 'none';
7791 * The function that should handle the trigger's click event. This method does nothing by default until overridden
7792 * by an implementing function.
7794 * @param {EventObject} e
7796 onTriggerClick : Roo.emptyFn
7800 * Ext JS Library 1.1.1
7801 * Copyright(c) 2006-2007, Ext JS, LLC.
7803 * Originally Released Under LGPL - original licence link has changed is not relivant.
7806 * <script type="text/javascript">
7811 * @class Roo.data.SortTypes
7813 * Defines the default sorting (casting?) comparison functions used when sorting data.
7815 Roo.data.SortTypes = {
7817 * Default sort that does nothing
7818 * @param {Mixed} s The value being converted
7819 * @return {Mixed} The comparison value
7826 * The regular expression used to strip tags
7830 stripTagsRE : /<\/?[^>]+>/gi,
7833 * Strips all HTML tags to sort on text only
7834 * @param {Mixed} s The value being converted
7835 * @return {String} The comparison value
7837 asText : function(s){
7838 return String(s).replace(this.stripTagsRE, "");
7842 * Strips all HTML tags to sort on text only - Case insensitive
7843 * @param {Mixed} s The value being converted
7844 * @return {String} The comparison value
7846 asUCText : function(s){
7847 return String(s).toUpperCase().replace(this.stripTagsRE, "");
7851 * Case insensitive string
7852 * @param {Mixed} s The value being converted
7853 * @return {String} The comparison value
7855 asUCString : function(s) {
7856 return String(s).toUpperCase();
7861 * @param {Mixed} s The value being converted
7862 * @return {Number} The comparison value
7864 asDate : function(s) {
7868 if(s instanceof Date){
7871 return Date.parse(String(s));
7876 * @param {Mixed} s The value being converted
7877 * @return {Float} The comparison value
7879 asFloat : function(s) {
7880 var val = parseFloat(String(s).replace(/,/g, ""));
7881 if(isNaN(val)) val = 0;
7887 * @param {Mixed} s The value being converted
7888 * @return {Number} The comparison value
7890 asInt : function(s) {
7891 var val = parseInt(String(s).replace(/,/g, ""));
7892 if(isNaN(val)) val = 0;
7897 * Ext JS Library 1.1.1
7898 * Copyright(c) 2006-2007, Ext JS, LLC.
7900 * Originally Released Under LGPL - original licence link has changed is not relivant.
7903 * <script type="text/javascript">
7907 * @class Roo.data.Record
7908 * Instances of this class encapsulate both record <em>definition</em> information, and record
7909 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
7910 * to access Records cached in an {@link Roo.data.Store} object.<br>
7912 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
7913 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
7916 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
7918 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
7919 * {@link #create}. The parameters are the same.
7920 * @param {Array} data An associative Array of data values keyed by the field name.
7921 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
7922 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
7923 * not specified an integer id is generated.
7925 Roo.data.Record = function(data, id){
7926 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
7931 * Generate a constructor for a specific record layout.
7932 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
7933 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
7934 * Each field definition object may contain the following properties: <ul>
7935 * <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,
7936 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
7937 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
7938 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
7939 * is being used, then this is a string containing the javascript expression to reference the data relative to
7940 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
7941 * to the data item relative to the record element. If the mapping expression is the same as the field name,
7942 * this may be omitted.</p></li>
7943 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
7944 * <ul><li>auto (Default, implies no conversion)</li>
7949 * <li>date</li></ul></p></li>
7950 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
7951 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
7952 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
7953 * by the Reader into an object that will be stored in the Record. It is passed the
7954 * following parameters:<ul>
7955 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
7957 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
7959 * <br>usage:<br><pre><code>
7960 var TopicRecord = Roo.data.Record.create(
7961 {name: 'title', mapping: 'topic_title'},
7962 {name: 'author', mapping: 'username'},
7963 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
7964 {name: 'lastPost', mapping: 'post_time', type: 'date'},
7965 {name: 'lastPoster', mapping: 'user2'},
7966 {name: 'excerpt', mapping: 'post_text'}
7969 var myNewRecord = new TopicRecord({
7970 title: 'Do my job please',
7973 lastPost: new Date(),
7974 lastPoster: 'Animal',
7975 excerpt: 'No way dude!'
7977 myStore.add(myNewRecord);
7982 Roo.data.Record.create = function(o){
7984 f.superclass.constructor.apply(this, arguments);
7986 Roo.extend(f, Roo.data.Record);
7987 var p = f.prototype;
7988 p.fields = new Roo.util.MixedCollection(false, function(field){
7991 for(var i = 0, len = o.length; i < len; i++){
7992 p.fields.add(new Roo.data.Field(o[i]));
7994 f.getField = function(name){
7995 return p.fields.get(name);
8000 Roo.data.Record.AUTO_ID = 1000;
8001 Roo.data.Record.EDIT = 'edit';
8002 Roo.data.Record.REJECT = 'reject';
8003 Roo.data.Record.COMMIT = 'commit';
8005 Roo.data.Record.prototype = {
8007 * Readonly flag - true if this record has been modified.
8016 join : function(store){
8021 * Set the named field to the specified value.
8022 * @param {String} name The name of the field to set.
8023 * @param {Object} value The value to set the field to.
8025 set : function(name, value){
8026 if(this.data[name] == value){
8033 if(typeof this.modified[name] == 'undefined'){
8034 this.modified[name] = this.data[name];
8036 this.data[name] = value;
8037 if(!this.editing && this.store){
8038 this.store.afterEdit(this);
8043 * Get the value of the named field.
8044 * @param {String} name The name of the field to get the value of.
8045 * @return {Object} The value of the field.
8047 get : function(name){
8048 return this.data[name];
8052 beginEdit : function(){
8053 this.editing = true;
8058 cancelEdit : function(){
8059 this.editing = false;
8060 delete this.modified;
8064 endEdit : function(){
8065 this.editing = false;
8066 if(this.dirty && this.store){
8067 this.store.afterEdit(this);
8072 * Usually called by the {@link Roo.data.Store} which owns the Record.
8073 * Rejects all changes made to the Record since either creation, or the last commit operation.
8074 * Modified fields are reverted to their original values.
8076 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8077 * of reject operations.
8079 reject : function(){
8080 var m = this.modified;
8082 if(typeof m[n] != "function"){
8083 this.data[n] = m[n];
8087 delete this.modified;
8088 this.editing = false;
8090 this.store.afterReject(this);
8095 * Usually called by the {@link Roo.data.Store} which owns the Record.
8096 * Commits all changes made to the Record since either creation, or the last commit operation.
8098 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8099 * of commit operations.
8101 commit : function(){
8103 delete this.modified;
8104 this.editing = false;
8106 this.store.afterCommit(this);
8111 hasError : function(){
8112 return this.error != null;
8116 clearError : function(){
8121 * Creates a copy of this record.
8122 * @param {String} id (optional) A new record id if you don't want to use this record's id
8125 copy : function(newId) {
8126 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8130 * Ext JS Library 1.1.1
8131 * Copyright(c) 2006-2007, Ext JS, LLC.
8133 * Originally Released Under LGPL - original licence link has changed is not relivant.
8136 * <script type="text/javascript">
8142 * @class Roo.data.Store
8143 * @extends Roo.util.Observable
8144 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8145 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8147 * 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
8148 * has no knowledge of the format of the data returned by the Proxy.<br>
8150 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8151 * instances from the data object. These records are cached and made available through accessor functions.
8153 * Creates a new Store.
8154 * @param {Object} config A config object containing the objects needed for the Store to access data,
8155 * and read the data into Records.
8157 Roo.data.Store = function(config){
8158 this.data = new Roo.util.MixedCollection(false);
8159 this.data.getKey = function(o){
8162 this.baseParams = {};
8169 "multisort" : "_multisort"
8172 if(config && config.data){
8173 this.inlineData = config.data;
8177 Roo.apply(this, config);
8179 if(this.reader){ // reader passed
8180 this.reader = Roo.factory(this.reader, Roo.data);
8181 this.reader.xmodule = this.xmodule || false;
8182 if(!this.recordType){
8183 this.recordType = this.reader.recordType;
8185 if(this.reader.onMetaChange){
8186 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8190 if(this.recordType){
8191 this.fields = this.recordType.prototype.fields;
8197 * @event datachanged
8198 * Fires when the data cache has changed, and a widget which is using this Store
8199 * as a Record cache should refresh its view.
8200 * @param {Store} this
8205 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8206 * @param {Store} this
8207 * @param {Object} meta The JSON metadata
8212 * Fires when Records have been added to the Store
8213 * @param {Store} this
8214 * @param {Roo.data.Record[]} records The array of Records added
8215 * @param {Number} index The index at which the record(s) were added
8220 * Fires when a Record has been removed from the Store
8221 * @param {Store} this
8222 * @param {Roo.data.Record} record The Record that was removed
8223 * @param {Number} index The index at which the record was removed
8228 * Fires when a Record has been updated
8229 * @param {Store} this
8230 * @param {Roo.data.Record} record The Record that was updated
8231 * @param {String} operation The update operation being performed. Value may be one of:
8233 Roo.data.Record.EDIT
8234 Roo.data.Record.REJECT
8235 Roo.data.Record.COMMIT
8241 * Fires when the data cache has been cleared.
8242 * @param {Store} this
8247 * Fires before a request is made for a new data object. If the beforeload handler returns false
8248 * the load action will be canceled.
8249 * @param {Store} this
8250 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8254 * @event beforeloadadd
8255 * Fires after a new set of Records has been loaded.
8256 * @param {Store} this
8257 * @param {Roo.data.Record[]} records The Records that were loaded
8258 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8260 beforeloadadd : true,
8263 * Fires after a new set of Records has been loaded, before they are added to the store.
8264 * @param {Store} this
8265 * @param {Roo.data.Record[]} records The Records that were loaded
8266 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8267 * @params {Object} return from reader
8271 * @event loadexception
8272 * Fires if an exception occurs in the Proxy during loading.
8273 * Called with the signature of the Proxy's "loadexception" event.
8274 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8277 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8278 * @param {Object} load options
8279 * @param {Object} jsonData from your request (normally this contains the Exception)
8281 loadexception : true
8285 this.proxy = Roo.factory(this.proxy, Roo.data);
8286 this.proxy.xmodule = this.xmodule || false;
8287 this.relayEvents(this.proxy, ["loadexception"]);
8289 this.sortToggle = {};
8290 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8292 Roo.data.Store.superclass.constructor.call(this);
8294 if(this.inlineData){
8295 this.loadData(this.inlineData);
8296 delete this.inlineData;
8300 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8302 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8303 * without a remote query - used by combo/forms at present.
8307 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8310 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8313 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8314 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8317 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8318 * on any HTTP request
8321 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8324 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8328 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8329 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8334 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8335 * loaded or when a record is removed. (defaults to false).
8337 pruneModifiedRecords : false,
8343 * Add Records to the Store and fires the add event.
8344 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8346 add : function(records){
8347 records = [].concat(records);
8348 for(var i = 0, len = records.length; i < len; i++){
8349 records[i].join(this);
8351 var index = this.data.length;
8352 this.data.addAll(records);
8353 this.fireEvent("add", this, records, index);
8357 * Remove a Record from the Store and fires the remove event.
8358 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8360 remove : function(record){
8361 var index = this.data.indexOf(record);
8362 this.data.removeAt(index);
8363 if(this.pruneModifiedRecords){
8364 this.modified.remove(record);
8366 this.fireEvent("remove", this, record, index);
8370 * Remove all Records from the Store and fires the clear event.
8372 removeAll : function(){
8374 if(this.pruneModifiedRecords){
8377 this.fireEvent("clear", this);
8381 * Inserts Records to the Store at the given index and fires the add event.
8382 * @param {Number} index The start index at which to insert the passed Records.
8383 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8385 insert : function(index, records){
8386 records = [].concat(records);
8387 for(var i = 0, len = records.length; i < len; i++){
8388 this.data.insert(index, records[i]);
8389 records[i].join(this);
8391 this.fireEvent("add", this, records, index);
8395 * Get the index within the cache of the passed Record.
8396 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8397 * @return {Number} The index of the passed Record. Returns -1 if not found.
8399 indexOf : function(record){
8400 return this.data.indexOf(record);
8404 * Get the index within the cache of the Record with the passed id.
8405 * @param {String} id The id of the Record to find.
8406 * @return {Number} The index of the Record. Returns -1 if not found.
8408 indexOfId : function(id){
8409 return this.data.indexOfKey(id);
8413 * Get the Record with the specified id.
8414 * @param {String} id The id of the Record to find.
8415 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8417 getById : function(id){
8418 return this.data.key(id);
8422 * Get the Record at the specified index.
8423 * @param {Number} index The index of the Record to find.
8424 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8426 getAt : function(index){
8427 return this.data.itemAt(index);
8431 * Returns a range of Records between specified indices.
8432 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8433 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8434 * @return {Roo.data.Record[]} An array of Records
8436 getRange : function(start, end){
8437 return this.data.getRange(start, end);
8441 storeOptions : function(o){
8442 o = Roo.apply({}, o);
8445 this.lastOptions = o;
8449 * Loads the Record cache from the configured Proxy using the configured Reader.
8451 * If using remote paging, then the first load call must specify the <em>start</em>
8452 * and <em>limit</em> properties in the options.params property to establish the initial
8453 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8455 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8456 * and this call will return before the new data has been loaded. Perform any post-processing
8457 * in a callback function, or in a "load" event handler.</strong>
8459 * @param {Object} options An object containing properties which control loading options:<ul>
8460 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8461 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8462 * passed the following arguments:<ul>
8463 * <li>r : Roo.data.Record[]</li>
8464 * <li>options: Options object from the load call</li>
8465 * <li>success: Boolean success indicator</li></ul></li>
8466 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8467 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8470 load : function(options){
8471 options = options || {};
8472 if(this.fireEvent("beforeload", this, options) !== false){
8473 this.storeOptions(options);
8474 var p = Roo.apply(options.params || {}, this.baseParams);
8475 // if meta was not loaded from remote source.. try requesting it.
8476 if (!this.reader.metaFromRemote) {
8479 if(this.sortInfo && this.remoteSort){
8480 var pn = this.paramNames;
8481 p[pn["sort"]] = this.sortInfo.field;
8482 p[pn["dir"]] = this.sortInfo.direction;
8484 if (this.multiSort) {
8485 var pn = this.paramNames;
8486 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8489 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8494 * Reloads the Record cache from the configured Proxy using the configured Reader and
8495 * the options from the last load operation performed.
8496 * @param {Object} options (optional) An object containing properties which may override the options
8497 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8498 * the most recently used options are reused).
8500 reload : function(options){
8501 this.load(Roo.applyIf(options||{}, this.lastOptions));
8505 // Called as a callback by the Reader during a load operation.
8506 loadRecords : function(o, options, success){
8507 if(!o || success === false){
8508 if(success !== false){
8509 this.fireEvent("load", this, [], options, o);
8511 if(options.callback){
8512 options.callback.call(options.scope || this, [], options, false);
8516 // if data returned failure - throw an exception.
8517 if (o.success === false) {
8518 // show a message if no listener is registered.
8519 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8520 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8522 // loadmask wil be hooked into this..
8523 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8526 var r = o.records, t = o.totalRecords || r.length;
8528 this.fireEvent("beforeloadadd", this, r, options, o);
8530 if(!options || options.add !== true){
8531 if(this.pruneModifiedRecords){
8534 for(var i = 0, len = r.length; i < len; i++){
8538 this.data = this.snapshot;
8539 delete this.snapshot;
8542 this.data.addAll(r);
8543 this.totalLength = t;
8545 this.fireEvent("datachanged", this);
8547 this.totalLength = Math.max(t, this.data.length+r.length);
8550 this.fireEvent("load", this, r, options, o);
8551 if(options.callback){
8552 options.callback.call(options.scope || this, r, options, true);
8558 * Loads data from a passed data block. A Reader which understands the format of the data
8559 * must have been configured in the constructor.
8560 * @param {Object} data The data block from which to read the Records. The format of the data expected
8561 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8562 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8564 loadData : function(o, append){
8565 var r = this.reader.readRecords(o);
8566 this.loadRecords(r, {add: append}, true);
8570 * Gets the number of cached records.
8572 * <em>If using paging, this may not be the total size of the dataset. If the data object
8573 * used by the Reader contains the dataset size, then the getTotalCount() function returns
8574 * the data set size</em>
8576 getCount : function(){
8577 return this.data.length || 0;
8581 * Gets the total number of records in the dataset as returned by the server.
8583 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8584 * the dataset size</em>
8586 getTotalCount : function(){
8587 return this.totalLength || 0;
8591 * Returns the sort state of the Store as an object with two properties:
8593 field {String} The name of the field by which the Records are sorted
8594 direction {String} The sort order, "ASC" or "DESC"
8597 getSortState : function(){
8598 return this.sortInfo;
8602 applySort : function(){
8603 if(this.sortInfo && !this.remoteSort){
8604 var s = this.sortInfo, f = s.field;
8605 var st = this.fields.get(f).sortType;
8606 var fn = function(r1, r2){
8607 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8608 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8610 this.data.sort(s.direction, fn);
8611 if(this.snapshot && this.snapshot != this.data){
8612 this.snapshot.sort(s.direction, fn);
8618 * Sets the default sort column and order to be used by the next load operation.
8619 * @param {String} fieldName The name of the field to sort by.
8620 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8622 setDefaultSort : function(field, dir){
8623 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
8628 * If remote sorting is used, the sort is performed on the server, and the cache is
8629 * reloaded. If local sorting is used, the cache is sorted internally.
8630 * @param {String} fieldName The name of the field to sort by.
8631 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8633 sort : function(fieldName, dir){
8634 var f = this.fields.get(fieldName);
8636 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
8638 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
8639 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
8644 this.sortToggle[f.name] = dir;
8645 this.sortInfo = {field: f.name, direction: dir};
8646 if(!this.remoteSort){
8648 this.fireEvent("datachanged", this);
8650 this.load(this.lastOptions);
8655 * Calls the specified function for each of the Records in the cache.
8656 * @param {Function} fn The function to call. The Record is passed as the first parameter.
8657 * Returning <em>false</em> aborts and exits the iteration.
8658 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
8660 each : function(fn, scope){
8661 this.data.each(fn, scope);
8665 * Gets all records modified since the last commit. Modified records are persisted across load operations
8666 * (e.g., during paging).
8667 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
8669 getModifiedRecords : function(){
8670 return this.modified;
8674 createFilterFn : function(property, value, anyMatch){
8675 if(!value.exec){ // not a regex
8676 value = String(value);
8677 if(value.length == 0){
8680 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
8683 return value.test(r.data[property]);
8688 * Sums the value of <i>property</i> for each record between start and end and returns the result.
8689 * @param {String} property A field on your records
8690 * @param {Number} start The record index to start at (defaults to 0)
8691 * @param {Number} end The last record index to include (defaults to length - 1)
8692 * @return {Number} The sum
8694 sum : function(property, start, end){
8695 var rs = this.data.items, v = 0;
8697 end = (end || end === 0) ? end : rs.length-1;
8699 for(var i = start; i <= end; i++){
8700 v += (rs[i].data[property] || 0);
8706 * Filter the records by a specified property.
8707 * @param {String} field A field on your records
8708 * @param {String/RegExp} value Either a string that the field
8709 * should start with or a RegExp to test against the field
8710 * @param {Boolean} anyMatch True to match any part not just the beginning
8712 filter : function(property, value, anyMatch){
8713 var fn = this.createFilterFn(property, value, anyMatch);
8714 return fn ? this.filterBy(fn) : this.clearFilter();
8718 * Filter by a function. The specified function will be called with each
8719 * record in this data source. If the function returns true the record is included,
8720 * otherwise it is filtered.
8721 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8722 * @param {Object} scope (optional) The scope of the function (defaults to this)
8724 filterBy : function(fn, scope){
8725 this.snapshot = this.snapshot || this.data;
8726 this.data = this.queryBy(fn, scope||this);
8727 this.fireEvent("datachanged", this);
8731 * Query the records by a specified property.
8732 * @param {String} field A field on your records
8733 * @param {String/RegExp} value Either a string that the field
8734 * should start with or a RegExp to test against the field
8735 * @param {Boolean} anyMatch True to match any part not just the beginning
8736 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8738 query : function(property, value, anyMatch){
8739 var fn = this.createFilterFn(property, value, anyMatch);
8740 return fn ? this.queryBy(fn) : this.data.clone();
8744 * Query by a function. The specified function will be called with each
8745 * record in this data source. If the function returns true the record is included
8747 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8748 * @param {Object} scope (optional) The scope of the function (defaults to this)
8749 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8751 queryBy : function(fn, scope){
8752 var data = this.snapshot || this.data;
8753 return data.filterBy(fn, scope||this);
8757 * Collects unique values for a particular dataIndex from this store.
8758 * @param {String} dataIndex The property to collect
8759 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
8760 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
8761 * @return {Array} An array of the unique values
8763 collect : function(dataIndex, allowNull, bypassFilter){
8764 var d = (bypassFilter === true && this.snapshot) ?
8765 this.snapshot.items : this.data.items;
8766 var v, sv, r = [], l = {};
8767 for(var i = 0, len = d.length; i < len; i++){
8768 v = d[i].data[dataIndex];
8770 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
8779 * Revert to a view of the Record cache with no filtering applied.
8780 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
8782 clearFilter : function(suppressEvent){
8783 if(this.snapshot && this.snapshot != this.data){
8784 this.data = this.snapshot;
8785 delete this.snapshot;
8786 if(suppressEvent !== true){
8787 this.fireEvent("datachanged", this);
8793 afterEdit : function(record){
8794 if(this.modified.indexOf(record) == -1){
8795 this.modified.push(record);
8797 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
8801 afterReject : function(record){
8802 this.modified.remove(record);
8803 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
8807 afterCommit : function(record){
8808 this.modified.remove(record);
8809 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
8813 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
8814 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
8816 commitChanges : function(){
8817 var m = this.modified.slice(0);
8819 for(var i = 0, len = m.length; i < len; i++){
8825 * Cancel outstanding changes on all changed records.
8827 rejectChanges : function(){
8828 var m = this.modified.slice(0);
8830 for(var i = 0, len = m.length; i < len; i++){
8835 onMetaChange : function(meta, rtype, o){
8836 this.recordType = rtype;
8837 this.fields = rtype.prototype.fields;
8838 delete this.snapshot;
8839 this.sortInfo = meta.sortInfo || this.sortInfo;
8841 this.fireEvent('metachange', this, this.reader.meta);
8844 moveIndex : function(data, type)
8846 var index = this.indexOf(data);
8848 var newIndex = index + type;
8852 this.insert(newIndex, data);
8857 * Ext JS Library 1.1.1
8858 * Copyright(c) 2006-2007, Ext JS, LLC.
8860 * Originally Released Under LGPL - original licence link has changed is not relivant.
8863 * <script type="text/javascript">
8867 * @class Roo.data.SimpleStore
8868 * @extends Roo.data.Store
8869 * Small helper class to make creating Stores from Array data easier.
8870 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
8871 * @cfg {Array} fields An array of field definition objects, or field name strings.
8872 * @cfg {Array} data The multi-dimensional array of data
8874 * @param {Object} config
8876 Roo.data.SimpleStore = function(config){
8877 Roo.data.SimpleStore.superclass.constructor.call(this, {
8879 reader: new Roo.data.ArrayReader({
8882 Roo.data.Record.create(config.fields)
8884 proxy : new Roo.data.MemoryProxy(config.data)
8888 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
8890 * Ext JS Library 1.1.1
8891 * Copyright(c) 2006-2007, Ext JS, LLC.
8893 * Originally Released Under LGPL - original licence link has changed is not relivant.
8896 * <script type="text/javascript">
8901 * @extends Roo.data.Store
8902 * @class Roo.data.JsonStore
8903 * Small helper class to make creating Stores for JSON data easier. <br/>
8905 var store = new Roo.data.JsonStore({
8906 url: 'get-images.php',
8908 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
8911 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
8912 * JsonReader and HttpProxy (unless inline data is provided).</b>
8913 * @cfg {Array} fields An array of field definition objects, or field name strings.
8915 * @param {Object} config
8917 Roo.data.JsonStore = function(c){
8918 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
8919 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
8920 reader: new Roo.data.JsonReader(c, c.fields)
8923 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
8925 * Ext JS Library 1.1.1
8926 * Copyright(c) 2006-2007, Ext JS, LLC.
8928 * Originally Released Under LGPL - original licence link has changed is not relivant.
8931 * <script type="text/javascript">
8935 Roo.data.Field = function(config){
8936 if(typeof config == "string"){
8937 config = {name: config};
8939 Roo.apply(this, config);
8945 var st = Roo.data.SortTypes;
8946 // named sortTypes are supported, here we look them up
8947 if(typeof this.sortType == "string"){
8948 this.sortType = st[this.sortType];
8951 // set default sortType for strings and dates
8955 this.sortType = st.asUCString;
8958 this.sortType = st.asDate;
8961 this.sortType = st.none;
8966 var stripRe = /[\$,%]/g;
8968 // prebuilt conversion function for this field, instead of
8969 // switching every time we're reading a value
8971 var cv, dateFormat = this.dateFormat;
8976 cv = function(v){ return v; };
8979 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
8983 return v !== undefined && v !== null && v !== '' ?
8984 parseInt(String(v).replace(stripRe, ""), 10) : '';
8989 return v !== undefined && v !== null && v !== '' ?
8990 parseFloat(String(v).replace(stripRe, ""), 10) : '';
8995 cv = function(v){ return v === true || v === "true" || v == 1; };
9002 if(v instanceof Date){
9006 if(dateFormat == "timestamp"){
9007 return new Date(v*1000);
9009 return Date.parseDate(v, dateFormat);
9011 var parsed = Date.parse(v);
9012 return parsed ? new Date(parsed) : null;
9021 Roo.data.Field.prototype = {
9029 * Ext JS Library 1.1.1
9030 * Copyright(c) 2006-2007, Ext JS, LLC.
9032 * Originally Released Under LGPL - original licence link has changed is not relivant.
9035 * <script type="text/javascript">
9038 // Base class for reading structured data from a data source. This class is intended to be
9039 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9042 * @class Roo.data.DataReader
9043 * Base class for reading structured data from a data source. This class is intended to be
9044 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9047 Roo.data.DataReader = function(meta, recordType){
9051 this.recordType = recordType instanceof Array ?
9052 Roo.data.Record.create(recordType) : recordType;
9055 Roo.data.DataReader.prototype = {
9057 * Create an empty record
9058 * @param {Object} data (optional) - overlay some values
9059 * @return {Roo.data.Record} record created.
9061 newRow : function(d) {
9063 this.recordType.prototype.fields.each(function(c) {
9065 case 'int' : da[c.name] = 0; break;
9066 case 'date' : da[c.name] = new Date(); break;
9067 case 'float' : da[c.name] = 0.0; break;
9068 case 'boolean' : da[c.name] = false; break;
9069 default : da[c.name] = ""; break;
9073 return new this.recordType(Roo.apply(da, d));
9078 * Ext JS Library 1.1.1
9079 * Copyright(c) 2006-2007, Ext JS, LLC.
9081 * Originally Released Under LGPL - original licence link has changed is not relivant.
9084 * <script type="text/javascript">
9088 * @class Roo.data.DataProxy
9089 * @extends Roo.data.Observable
9090 * This class is an abstract base class for implementations which provide retrieval of
9091 * unformatted data objects.<br>
9093 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9094 * (of the appropriate type which knows how to parse the data object) to provide a block of
9095 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9097 * Custom implementations must implement the load method as described in
9098 * {@link Roo.data.HttpProxy#load}.
9100 Roo.data.DataProxy = function(){
9104 * Fires before a network request is made to retrieve a data object.
9105 * @param {Object} This DataProxy object.
9106 * @param {Object} params The params parameter to the load function.
9111 * Fires before the load method's callback is called.
9112 * @param {Object} This DataProxy object.
9113 * @param {Object} o The data object.
9114 * @param {Object} arg The callback argument object passed to the load function.
9118 * @event loadexception
9119 * Fires if an Exception occurs during data retrieval.
9120 * @param {Object} This DataProxy object.
9121 * @param {Object} o The data object.
9122 * @param {Object} arg The callback argument object passed to the load function.
9123 * @param {Object} e The Exception.
9125 loadexception : true
9127 Roo.data.DataProxy.superclass.constructor.call(this);
9130 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9133 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9137 * Ext JS Library 1.1.1
9138 * Copyright(c) 2006-2007, Ext JS, LLC.
9140 * Originally Released Under LGPL - original licence link has changed is not relivant.
9143 * <script type="text/javascript">
9146 * @class Roo.data.MemoryProxy
9147 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9148 * to the Reader when its load method is called.
9150 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9152 Roo.data.MemoryProxy = function(data){
9156 Roo.data.MemoryProxy.superclass.constructor.call(this);
9160 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9162 * Load data from the requested source (in this case an in-memory
9163 * data object passed to the constructor), read the data object into
9164 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9165 * process that block using the passed callback.
9166 * @param {Object} params This parameter is not used by the MemoryProxy class.
9167 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9168 * object into a block of Roo.data.Records.
9169 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9170 * The function must be passed <ul>
9171 * <li>The Record block object</li>
9172 * <li>The "arg" argument from the load function</li>
9173 * <li>A boolean success indicator</li>
9175 * @param {Object} scope The scope in which to call the callback
9176 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9178 load : function(params, reader, callback, scope, arg){
9179 params = params || {};
9182 result = reader.readRecords(this.data);
9184 this.fireEvent("loadexception", this, arg, null, e);
9185 callback.call(scope, null, arg, false);
9188 callback.call(scope, result, arg, true);
9192 update : function(params, records){
9197 * Ext JS Library 1.1.1
9198 * Copyright(c) 2006-2007, Ext JS, LLC.
9200 * Originally Released Under LGPL - original licence link has changed is not relivant.
9203 * <script type="text/javascript">
9206 * @class Roo.data.HttpProxy
9207 * @extends Roo.data.DataProxy
9208 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9209 * configured to reference a certain URL.<br><br>
9211 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9212 * from which the running page was served.<br><br>
9214 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9216 * Be aware that to enable the browser to parse an XML document, the server must set
9217 * the Content-Type header in the HTTP response to "text/xml".
9219 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9220 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9221 * will be used to make the request.
9223 Roo.data.HttpProxy = function(conn){
9224 Roo.data.HttpProxy.superclass.constructor.call(this);
9225 // is conn a conn config or a real conn?
9227 this.useAjax = !conn || !conn.events;
9231 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9232 // thse are take from connection...
9235 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9238 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9239 * extra parameters to each request made by this object. (defaults to undefined)
9242 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9243 * to each request made by this object. (defaults to undefined)
9246 * @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)
9249 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9252 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9258 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9262 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9263 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9264 * a finer-grained basis than the DataProxy events.
9266 getConnection : function(){
9267 return this.useAjax ? Roo.Ajax : this.conn;
9271 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9272 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9273 * process that block using the passed callback.
9274 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9275 * for the request to the remote server.
9276 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9277 * object into a block of Roo.data.Records.
9278 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9279 * The function must be passed <ul>
9280 * <li>The Record block object</li>
9281 * <li>The "arg" argument from the load function</li>
9282 * <li>A boolean success indicator</li>
9284 * @param {Object} scope The scope in which to call the callback
9285 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9287 load : function(params, reader, callback, scope, arg){
9288 if(this.fireEvent("beforeload", this, params) !== false){
9290 params : params || {},
9292 callback : callback,
9297 callback : this.loadResponse,
9301 Roo.applyIf(o, this.conn);
9302 if(this.activeRequest){
9303 Roo.Ajax.abort(this.activeRequest);
9305 this.activeRequest = Roo.Ajax.request(o);
9307 this.conn.request(o);
9310 callback.call(scope||this, null, arg, false);
9315 loadResponse : function(o, success, response){
9316 delete this.activeRequest;
9318 this.fireEvent("loadexception", this, o, response);
9319 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9324 result = o.reader.read(response);
9326 this.fireEvent("loadexception", this, o, response, e);
9327 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9331 this.fireEvent("load", this, o, o.request.arg);
9332 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9336 update : function(dataSet){
9341 updateResponse : function(dataSet){
9346 * Ext JS Library 1.1.1
9347 * Copyright(c) 2006-2007, Ext JS, LLC.
9349 * Originally Released Under LGPL - original licence link has changed is not relivant.
9352 * <script type="text/javascript">
9356 * @class Roo.data.ScriptTagProxy
9357 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9358 * other than the originating domain of the running page.<br><br>
9360 * <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
9361 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9363 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9364 * source code that is used as the source inside a <script> tag.<br><br>
9366 * In order for the browser to process the returned data, the server must wrap the data object
9367 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9368 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9369 * depending on whether the callback name was passed:
9372 boolean scriptTag = false;
9373 String cb = request.getParameter("callback");
9376 response.setContentType("text/javascript");
9378 response.setContentType("application/x-json");
9380 Writer out = response.getWriter();
9382 out.write(cb + "(");
9384 out.print(dataBlock.toJsonString());
9391 * @param {Object} config A configuration object.
9393 Roo.data.ScriptTagProxy = function(config){
9394 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9395 Roo.apply(this, config);
9396 this.head = document.getElementsByTagName("head")[0];
9399 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9401 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9403 * @cfg {String} url The URL from which to request the data object.
9406 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9410 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9411 * the server the name of the callback function set up by the load call to process the returned data object.
9412 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9413 * javascript output which calls this named function passing the data object as its only parameter.
9415 callbackParam : "callback",
9417 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9418 * name to the request.
9423 * Load data from the configured URL, read the data object into
9424 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9425 * process that block using the passed callback.
9426 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9427 * for the request to the remote server.
9428 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9429 * object into a block of Roo.data.Records.
9430 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9431 * The function must be passed <ul>
9432 * <li>The Record block object</li>
9433 * <li>The "arg" argument from the load function</li>
9434 * <li>A boolean success indicator</li>
9436 * @param {Object} scope The scope in which to call the callback
9437 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9439 load : function(params, reader, callback, scope, arg){
9440 if(this.fireEvent("beforeload", this, params) !== false){
9442 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9445 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9447 url += "&_dc=" + (new Date().getTime());
9449 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9452 cb : "stcCallback"+transId,
9453 scriptId : "stcScript"+transId,
9457 callback : callback,
9463 window[trans.cb] = function(o){
9464 conn.handleResponse(o, trans);
9467 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9469 if(this.autoAbort !== false){
9473 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9475 var script = document.createElement("script");
9476 script.setAttribute("src", url);
9477 script.setAttribute("type", "text/javascript");
9478 script.setAttribute("id", trans.scriptId);
9479 this.head.appendChild(script);
9483 callback.call(scope||this, null, arg, false);
9488 isLoading : function(){
9489 return this.trans ? true : false;
9493 * Abort the current server request.
9496 if(this.isLoading()){
9497 this.destroyTrans(this.trans);
9502 destroyTrans : function(trans, isLoaded){
9503 this.head.removeChild(document.getElementById(trans.scriptId));
9504 clearTimeout(trans.timeoutId);
9506 window[trans.cb] = undefined;
9508 delete window[trans.cb];
9511 // if hasn't been loaded, wait for load to remove it to prevent script error
9512 window[trans.cb] = function(){
9513 window[trans.cb] = undefined;
9515 delete window[trans.cb];
9522 handleResponse : function(o, trans){
9524 this.destroyTrans(trans, true);
9527 result = trans.reader.readRecords(o);
9529 this.fireEvent("loadexception", this, o, trans.arg, e);
9530 trans.callback.call(trans.scope||window, null, trans.arg, false);
9533 this.fireEvent("load", this, o, trans.arg);
9534 trans.callback.call(trans.scope||window, result, trans.arg, true);
9538 handleFailure : function(trans){
9540 this.destroyTrans(trans, false);
9541 this.fireEvent("loadexception", this, null, trans.arg);
9542 trans.callback.call(trans.scope||window, null, trans.arg, false);
9546 * Ext JS Library 1.1.1
9547 * Copyright(c) 2006-2007, Ext JS, LLC.
9549 * Originally Released Under LGPL - original licence link has changed is not relivant.
9552 * <script type="text/javascript">
9556 * @class Roo.data.JsonReader
9557 * @extends Roo.data.DataReader
9558 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9559 * based on mappings in a provided Roo.data.Record constructor.
9561 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9562 * in the reply previously.
9567 var RecordDef = Roo.data.Record.create([
9568 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
9569 {name: 'occupation'} // This field will use "occupation" as the mapping.
9571 var myReader = new Roo.data.JsonReader({
9572 totalProperty: "results", // The property which contains the total dataset size (optional)
9573 root: "rows", // The property which contains an Array of row objects
9574 id: "id" // The property within each row object that provides an ID for the record (optional)
9578 * This would consume a JSON file like this:
9580 { 'results': 2, 'rows': [
9581 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9582 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9585 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9586 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9587 * paged from the remote server.
9588 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9589 * @cfg {String} root name of the property which contains the Array of row objects.
9590 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9592 * Create a new JsonReader
9593 * @param {Object} meta Metadata configuration options
9594 * @param {Object} recordType Either an Array of field definition objects,
9595 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9597 Roo.data.JsonReader = function(meta, recordType){
9600 // set some defaults:
9602 totalProperty: 'total',
9603 successProperty : 'success',
9608 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9610 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9613 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
9614 * Used by Store query builder to append _requestMeta to params.
9617 metaFromRemote : false,
9619 * This method is only used by a DataProxy which has retrieved data from a remote server.
9620 * @param {Object} response The XHR object which contains the JSON data in its responseText.
9621 * @return {Object} data A data block which is used by an Roo.data.Store object as
9622 * a cache of Roo.data.Records.
9624 read : function(response){
9625 var json = response.responseText;
9627 var o = /* eval:var:o */ eval("("+json+")");
9629 throw {message: "JsonReader.read: Json object not found"};
9635 this.metaFromRemote = true;
9636 this.meta = o.metaData;
9637 this.recordType = Roo.data.Record.create(o.metaData.fields);
9638 this.onMetaChange(this.meta, this.recordType, o);
9640 return this.readRecords(o);
9643 // private function a store will implement
9644 onMetaChange : function(meta, recordType, o){
9651 simpleAccess: function(obj, subsc) {
9658 getJsonAccessor: function(){
9660 return function(expr) {
9662 return(re.test(expr))
9663 ? new Function("obj", "return obj." + expr)
9673 * Create a data block containing Roo.data.Records from an XML document.
9674 * @param {Object} o An object which contains an Array of row objects in the property specified
9675 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
9676 * which contains the total size of the dataset.
9677 * @return {Object} data A data block which is used by an Roo.data.Store object as
9678 * a cache of Roo.data.Records.
9680 readRecords : function(o){
9682 * After any data loads, the raw JSON data is available for further custom processing.
9686 var s = this.meta, Record = this.recordType,
9687 f = Record.prototype.fields, fi = f.items, fl = f.length;
9689 // Generate extraction functions for the totalProperty, the root, the id, and for each field
9691 if(s.totalProperty) {
9692 this.getTotal = this.getJsonAccessor(s.totalProperty);
9694 if(s.successProperty) {
9695 this.getSuccess = this.getJsonAccessor(s.successProperty);
9697 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
9699 var g = this.getJsonAccessor(s.id);
9700 this.getId = function(rec) {
9702 return (r === undefined || r === "") ? null : r;
9705 this.getId = function(){return null;};
9708 for(var jj = 0; jj < fl; jj++){
9710 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
9711 this.ef[jj] = this.getJsonAccessor(map);
9715 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
9716 if(s.totalProperty){
9717 var vt = parseInt(this.getTotal(o), 10);
9722 if(s.successProperty){
9723 var vs = this.getSuccess(o);
9724 if(vs === false || vs === 'false'){
9729 for(var i = 0; i < c; i++){
9732 var id = this.getId(n);
9733 for(var j = 0; j < fl; j++){
9735 var v = this.ef[j](n);
9737 Roo.log('missing convert for ' + f.name);
9741 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
9743 var record = new Record(values, id);
9745 records[i] = record;
9751 totalRecords : totalRecords
9756 * Ext JS Library 1.1.1
9757 * Copyright(c) 2006-2007, Ext JS, LLC.
9759 * Originally Released Under LGPL - original licence link has changed is not relivant.
9762 * <script type="text/javascript">
9766 * @class Roo.data.ArrayReader
9767 * @extends Roo.data.DataReader
9768 * Data reader class to create an Array of Roo.data.Record objects from an Array.
9769 * Each element of that Array represents a row of data fields. The
9770 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
9771 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
9775 var RecordDef = Roo.data.Record.create([
9776 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
9777 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
9779 var myReader = new Roo.data.ArrayReader({
9780 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
9784 * This would consume an Array like this:
9786 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
9788 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
9790 * Create a new JsonReader
9791 * @param {Object} meta Metadata configuration options.
9792 * @param {Object} recordType Either an Array of field definition objects
9793 * as specified to {@link Roo.data.Record#create},
9794 * or an {@link Roo.data.Record} object
9795 * created using {@link Roo.data.Record#create}.
9797 Roo.data.ArrayReader = function(meta, recordType){
9798 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
9801 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
9803 * Create a data block containing Roo.data.Records from an XML document.
9804 * @param {Object} o An Array of row objects which represents the dataset.
9805 * @return {Object} data A data block which is used by an Roo.data.Store object as
9806 * a cache of Roo.data.Records.
9808 readRecords : function(o){
9809 var sid = this.meta ? this.meta.id : null;
9810 var recordType = this.recordType, fields = recordType.prototype.fields;
9813 for(var i = 0; i < root.length; i++){
9816 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
9817 for(var j = 0, jlen = fields.length; j < jlen; j++){
9818 var f = fields.items[j];
9819 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
9820 var v = n[k] !== undefined ? n[k] : f.defaultValue;
9824 var record = new recordType(values, id);
9826 records[records.length] = record;
9830 totalRecords : records.length
9839 * @class Roo.bootstrap.ComboBox
9840 * @extends Roo.bootstrap.TriggerField
9841 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
9842 * @cfg {Boolean} append (true|false) default false
9843 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
9844 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
9845 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
9847 * Create a new ComboBox.
9848 * @param {Object} config Configuration options
9850 Roo.bootstrap.ComboBox = function(config){
9851 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
9855 * Fires when the dropdown list is expanded
9856 * @param {Roo.bootstrap.ComboBox} combo This combo box
9861 * Fires when the dropdown list is collapsed
9862 * @param {Roo.bootstrap.ComboBox} combo This combo box
9866 * @event beforeselect
9867 * Fires before a list item is selected. Return false to cancel the selection.
9868 * @param {Roo.bootstrap.ComboBox} combo This combo box
9869 * @param {Roo.data.Record} record The data record returned from the underlying store
9870 * @param {Number} index The index of the selected item in the dropdown list
9872 'beforeselect' : true,
9875 * Fires when a list item is selected
9876 * @param {Roo.bootstrap.ComboBox} combo This combo box
9877 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
9878 * @param {Number} index The index of the selected item in the dropdown list
9882 * @event beforequery
9883 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
9884 * The event object passed has these properties:
9885 * @param {Roo.bootstrap.ComboBox} combo This combo box
9886 * @param {String} query The query
9887 * @param {Boolean} forceAll true to force "all" query
9888 * @param {Boolean} cancel true to cancel the query
9889 * @param {Object} e The query event object
9891 'beforequery': true,
9894 * Fires when the 'add' icon is pressed (add a listener to enable add button)
9895 * @param {Roo.bootstrap.ComboBox} combo This combo box
9900 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
9901 * @param {Roo.bootstrap.ComboBox} combo This combo box
9902 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
9907 * Fires when the remove value from the combobox array
9908 * @param {Roo.bootstrap.ComboBox} combo This combo box
9915 this.tickItems = [];
9917 this.selectedIndex = -1;
9918 if(this.mode == 'local'){
9919 if(config.queryDelay === undefined){
9920 this.queryDelay = 10;
9922 if(config.minChars === undefined){
9928 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
9931 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
9932 * rendering into an Roo.Editor, defaults to false)
9935 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
9936 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
9939 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
9942 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
9943 * the dropdown list (defaults to undefined, with no header element)
9947 * @cfg {String/Roo.Template} tpl The template to use to render the output
9951 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
9953 listWidth: undefined,
9955 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
9956 * mode = 'remote' or 'text' if mode = 'local')
9958 displayField: undefined,
9960 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
9961 * mode = 'remote' or 'value' if mode = 'local').
9962 * Note: use of a valueField requires the user make a selection
9963 * in order for a value to be mapped.
9965 valueField: undefined,
9969 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
9970 * field's data value (defaults to the underlying DOM element's name)
9972 hiddenName: undefined,
9974 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
9978 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
9980 selectedClass: 'active',
9983 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
9987 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
9988 * anchor positions (defaults to 'tl-bl')
9990 listAlign: 'tl-bl?',
9992 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
9996 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
9997 * query specified by the allQuery config option (defaults to 'query')
9999 triggerAction: 'query',
10001 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10002 * (defaults to 4, does not apply if editable = false)
10006 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10007 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10011 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10012 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10016 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10017 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10021 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10022 * when editable = true (defaults to false)
10024 selectOnFocus:false,
10026 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10028 queryParam: 'query',
10030 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10031 * when mode = 'remote' (defaults to 'Loading...')
10033 loadingText: 'Loading...',
10035 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10039 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10043 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10044 * traditional select (defaults to true)
10048 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10052 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10056 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10057 * listWidth has a higher value)
10061 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10062 * allow the user to set arbitrary text into the field (defaults to false)
10064 forceSelection:false,
10066 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10067 * if typeAhead = true (defaults to 250)
10069 typeAheadDelay : 250,
10071 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10072 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10074 valueNotFoundText : undefined,
10076 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10078 blockFocus : false,
10081 * @cfg {Boolean} disableClear Disable showing of clear button.
10083 disableClear : false,
10085 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10087 alwaysQuery : false,
10090 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10104 btnPosition : 'right',
10106 // element that contains real text value.. (when hidden is used..)
10108 getAutoCreate : function()
10115 if(!this.tickable){
10116 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10121 * ComboBox with tickable selections
10124 var align = this.labelAlign || this.parentLabelAlign();
10127 cls : 'form-group roo-combobox-tickable' //input-group
10133 cls : 'tickable-buttons',
10138 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10145 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10152 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10159 Roo.each(buttons.cn, function(c){
10161 c.cls += ' btn-' + _this.size;
10164 if (_this.disabled) {
10175 cls: 'form-hidden-field'
10179 cls: 'select2-choices',
10183 cls: 'select2-search-field',
10195 cls: 'select2-container input-group select2-container-multi',
10200 cls: 'typeahead typeahead-long dropdown-menu',
10201 style: 'display:none; max-height:' + this.maxHeight + 'px;'
10206 if (align ==='left' && this.fieldLabel.length) {
10208 Roo.log("left and has label");
10214 cls : 'control-label col-sm-' + this.labelWidth,
10215 html : this.fieldLabel
10219 cls : "col-sm-" + (12 - this.labelWidth),
10226 } else if ( this.fieldLabel.length) {
10232 //cls : 'input-group-addon',
10233 html : this.fieldLabel
10243 Roo.log(" no label && no align");
10250 ['xs','sm','md','lg'].map(function(size){
10251 if (settings[size]) {
10252 cfg.cls += ' col-' + size + '-' + settings[size];
10261 initEvents: function()
10265 throw "can not find store for combo";
10267 this.store = Roo.factory(this.store, Roo.data);
10270 this.initTickableEvnets();
10274 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10277 if(this.hiddenName){
10279 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10281 this.hiddenField.dom.value =
10282 this.hiddenValue !== undefined ? this.hiddenValue :
10283 this.value !== undefined ? this.value : '';
10285 // prevent input submission
10286 this.el.dom.removeAttribute('name');
10287 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10292 // this.el.dom.setAttribute('autocomplete', 'off');
10295 var cls = 'x-combo-list';
10296 this.list = this.el.select('ul.dropdown-menu',true).first();
10298 //this.list = new Roo.Layer({
10299 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10305 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10306 _this.list.setWidth(lw);
10309 this.list.on('mouseover', this.onViewOver, this);
10310 this.list.on('mousemove', this.onViewMove, this);
10312 this.list.on('scroll', this.onViewScroll, this);
10315 this.list.swallowEvent('mousewheel');
10316 this.assetHeight = 0;
10319 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10320 this.assetHeight += this.header.getHeight();
10323 this.innerList = this.list.createChild({cls:cls+'-inner'});
10324 this.innerList.on('mouseover', this.onViewOver, this);
10325 this.innerList.on('mousemove', this.onViewMove, this);
10326 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10328 if(this.allowBlank && !this.pageSize && !this.disableClear){
10329 this.footer = this.list.createChild({cls:cls+'-ft'});
10330 this.pageTb = new Roo.Toolbar(this.footer);
10334 this.footer = this.list.createChild({cls:cls+'-ft'});
10335 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10336 {pageSize: this.pageSize});
10340 if (this.pageTb && this.allowBlank && !this.disableClear) {
10342 this.pageTb.add(new Roo.Toolbar.Fill(), {
10343 cls: 'x-btn-icon x-btn-clear',
10345 handler: function()
10348 _this.clearValue();
10349 _this.onSelect(false, -1);
10354 this.assetHeight += this.footer.getHeight();
10359 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10362 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
10363 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10365 //this.view.wrapEl.setDisplayed(false);
10366 this.view.on('click', this.onViewClick, this);
10370 this.store.on('beforeload', this.onBeforeLoad, this);
10371 this.store.on('load', this.onLoad, this);
10372 this.store.on('loadexception', this.onLoadException, this);
10374 if(this.resizable){
10375 this.resizer = new Roo.Resizable(this.list, {
10376 pinned:true, handles:'se'
10378 this.resizer.on('resize', function(r, w, h){
10379 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10380 this.listWidth = w;
10381 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10382 this.restrictHeight();
10384 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10387 if(!this.editable){
10388 this.editable = true;
10389 this.setEditable(false);
10394 if (typeof(this.events.add.listeners) != 'undefined') {
10396 this.addicon = this.wrap.createChild(
10397 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10399 this.addicon.on('click', function(e) {
10400 this.fireEvent('add', this);
10403 if (typeof(this.events.edit.listeners) != 'undefined') {
10405 this.editicon = this.wrap.createChild(
10406 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10407 if (this.addicon) {
10408 this.editicon.setStyle('margin-left', '40px');
10410 this.editicon.on('click', function(e) {
10412 // we fire even if inothing is selected..
10413 this.fireEvent('edit', this, this.lastData );
10419 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10420 "up" : function(e){
10421 this.inKeyMode = true;
10425 "down" : function(e){
10426 if(!this.isExpanded()){
10427 this.onTriggerClick();
10429 this.inKeyMode = true;
10434 "enter" : function(e){
10435 // this.onViewClick();
10439 if(this.fireEvent("specialkey", this, e)){
10440 this.onViewClick(false);
10446 "esc" : function(e){
10450 "tab" : function(e){
10453 if(this.fireEvent("specialkey", this, e)){
10454 this.onViewClick(false);
10462 doRelay : function(foo, bar, hname){
10463 if(hname == 'down' || this.scope.isExpanded()){
10464 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10473 this.queryDelay = Math.max(this.queryDelay || 10,
10474 this.mode == 'local' ? 10 : 250);
10477 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10479 if(this.typeAhead){
10480 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10482 if(this.editable !== false){
10483 this.inputEl().on("keyup", this.onKeyUp, this);
10485 if(this.forceSelection){
10486 this.inputEl().on('blur', this.doForce, this);
10490 this.choices = this.el.select('ul.select2-choices', true).first();
10491 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10495 initTickableEvnets: function()
10497 if(this.hiddenName){
10499 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10501 this.hiddenField.dom.value =
10502 this.hiddenValue !== undefined ? this.hiddenValue :
10503 this.value !== undefined ? this.value : '';
10505 // prevent input submission
10506 this.el.dom.removeAttribute('name');
10507 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10512 this.list = this.el.select('ul.dropdown-menu',true).first();
10514 this.choices = this.el.select('ul.select2-choices', true).first();
10515 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10516 this.searchField.on("click", this.onTriggerClick, this, {preventDefault:true});
10518 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10519 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10521 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10522 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10524 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10525 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10527 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10528 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10529 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10532 this.cancelBtn.hide();
10537 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10538 _this.list.setWidth(lw);
10541 this.list.on('mouseover', this.onViewOver, this);
10542 this.list.on('mousemove', this.onViewMove, this);
10544 this.list.on('scroll', this.onViewScroll, this);
10547 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>';
10550 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
10551 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10554 //this.view.wrapEl.setDisplayed(false);
10555 this.view.on('click', this.onViewClick, this);
10559 this.store.on('beforeload', this.onBeforeLoad, this);
10560 this.store.on('load', this.onLoad, this);
10561 this.store.on('loadexception', this.onLoadException, this);
10563 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
10564 // "up" : function(e){
10565 // this.inKeyMode = true;
10566 // this.selectPrev();
10569 // "down" : function(e){
10570 // if(!this.isExpanded()){
10571 // this.onTriggerClick();
10573 // this.inKeyMode = true;
10574 // this.selectNext();
10578 // "enter" : function(e){
10579 //// this.onViewClick();
10581 // this.collapse();
10583 // if(this.fireEvent("specialkey", this, e)){
10584 // this.onViewClick(false);
10590 // "esc" : function(e){
10591 // this.collapse();
10594 // "tab" : function(e){
10595 // this.collapse();
10597 // if(this.fireEvent("specialkey", this, e)){
10598 // this.onViewClick(false);
10606 // doRelay : function(foo, bar, hname){
10607 // if(hname == 'down' || this.scope.isExpanded()){
10608 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10613 // forceKeyDown: true
10617 this.queryDelay = Math.max(this.queryDelay || 10,
10618 this.mode == 'local' ? 10 : 250);
10621 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10623 if(this.typeAhead){
10624 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10628 onDestroy : function(){
10630 this.view.setStore(null);
10631 this.view.el.removeAllListeners();
10632 this.view.el.remove();
10633 this.view.purgeListeners();
10636 this.list.dom.innerHTML = '';
10640 this.store.un('beforeload', this.onBeforeLoad, this);
10641 this.store.un('load', this.onLoad, this);
10642 this.store.un('loadexception', this.onLoadException, this);
10644 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
10648 fireKey : function(e){
10649 if(e.isNavKeyPress() && !this.list.isVisible()){
10650 this.fireEvent("specialkey", this, e);
10655 onResize: function(w, h){
10656 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
10658 // if(typeof w != 'number'){
10659 // // we do not handle it!?!?
10662 // var tw = this.trigger.getWidth();
10663 // // tw += this.addicon ? this.addicon.getWidth() : 0;
10664 // // tw += this.editicon ? this.editicon.getWidth() : 0;
10666 // this.inputEl().setWidth( this.adjustWidth('input', x));
10668 // //this.trigger.setStyle('left', x+'px');
10670 // if(this.list && this.listWidth === undefined){
10671 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
10672 // this.list.setWidth(lw);
10673 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10681 * Allow or prevent the user from directly editing the field text. If false is passed,
10682 * the user will only be able to select from the items defined in the dropdown list. This method
10683 * is the runtime equivalent of setting the 'editable' config option at config time.
10684 * @param {Boolean} value True to allow the user to directly edit the field text
10686 setEditable : function(value){
10687 if(value == this.editable){
10690 this.editable = value;
10692 this.inputEl().dom.setAttribute('readOnly', true);
10693 this.inputEl().on('mousedown', this.onTriggerClick, this);
10694 this.inputEl().addClass('x-combo-noedit');
10696 this.inputEl().dom.setAttribute('readOnly', false);
10697 this.inputEl().un('mousedown', this.onTriggerClick, this);
10698 this.inputEl().removeClass('x-combo-noedit');
10704 onBeforeLoad : function(combo,opts){
10705 if(!this.hasFocus){
10709 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
10711 this.restrictHeight();
10712 this.selectedIndex = -1;
10716 onLoad : function(){
10718 this.hasQuery = false;
10720 if(!this.hasFocus){
10724 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10725 this.loading.hide();
10728 if(this.store.getCount() > 0){
10730 this.restrictHeight();
10731 if(this.lastQuery == this.allQuery){
10732 if(this.editable && !this.tickable){
10733 this.inputEl().dom.select();
10735 if(!this.selectByValue(this.value, true) && this.autoFocus){
10736 this.select(0, true);
10739 if(this.autoFocus){
10742 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
10743 this.taTask.delay(this.typeAheadDelay);
10747 this.onEmptyResults();
10753 onLoadException : function()
10755 this.hasQuery = false;
10757 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10758 this.loading.hide();
10762 Roo.log(this.store.reader.jsonData);
10763 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
10765 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
10771 onTypeAhead : function(){
10772 if(this.store.getCount() > 0){
10773 var r = this.store.getAt(0);
10774 var newValue = r.data[this.displayField];
10775 var len = newValue.length;
10776 var selStart = this.getRawValue().length;
10778 if(selStart != len){
10779 this.setRawValue(newValue);
10780 this.selectText(selStart, newValue.length);
10786 onSelect : function(record, index){
10788 if(this.fireEvent('beforeselect', this, record, index) !== false){
10790 this.setFromData(index > -1 ? record.data : false);
10793 this.fireEvent('select', this, record, index);
10798 * Returns the currently selected field value or empty string if no value is set.
10799 * @return {String} value The selected value
10801 getValue : function(){
10804 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
10807 if(this.valueField){
10808 return typeof this.value != 'undefined' ? this.value : '';
10810 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
10815 * Clears any text/value currently set in the field
10817 clearValue : function(){
10818 if(this.hiddenField){
10819 this.hiddenField.dom.value = '';
10822 this.setRawValue('');
10823 this.lastSelectionText = '';
10828 * Sets the specified value into the field. If the value finds a match, the corresponding record text
10829 * will be displayed in the field. If the value does not match the data value of an existing item,
10830 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
10831 * Otherwise the field will be blank (although the value will still be set).
10832 * @param {String} value The value to match
10834 setValue : function(v){
10841 if(this.valueField){
10842 var r = this.findRecord(this.valueField, v);
10844 text = r.data[this.displayField];
10845 }else if(this.valueNotFoundText !== undefined){
10846 text = this.valueNotFoundText;
10849 this.lastSelectionText = text;
10850 if(this.hiddenField){
10851 this.hiddenField.dom.value = v;
10853 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
10857 * @property {Object} the last set data for the element
10862 * Sets the value of the field based on a object which is related to the record format for the store.
10863 * @param {Object} value the value to set as. or false on reset?
10865 setFromData : function(o){
10872 var dv = ''; // display value
10873 var vv = ''; // value value..
10875 if (this.displayField) {
10876 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
10878 // this is an error condition!!!
10879 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
10882 if(this.valueField){
10883 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
10886 if(this.hiddenField){
10887 this.hiddenField.dom.value = vv;
10889 this.lastSelectionText = dv;
10890 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
10894 // no hidden field.. - we store the value in 'value', but still display
10895 // display field!!!!
10896 this.lastSelectionText = dv;
10897 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
10903 reset : function(){
10904 // overridden so that last data is reset..
10905 this.setValue(this.originalValue);
10906 this.clearInvalid();
10907 this.lastData = false;
10909 this.view.clearSelections();
10913 findRecord : function(prop, value){
10915 if(this.store.getCount() > 0){
10916 this.store.each(function(r){
10917 if(r.data[prop] == value){
10927 getName: function()
10929 // returns hidden if it's set..
10930 if (!this.rendered) {return ''};
10931 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
10935 onViewMove : function(e, t){
10936 this.inKeyMode = false;
10940 onViewOver : function(e, t){
10941 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
10944 var item = this.view.findItemFromChild(t);
10947 var index = this.view.indexOf(item);
10948 this.select(index, false);
10953 onViewClick : function(view, doFocus, el, e)
10955 var index = this.view.getSelectedIndexes()[0];
10957 var r = this.store.getAt(index);
10961 if(e.getTarget().nodeName.toLowerCase() != 'input'){
10968 Roo.each(this.tickItems, function(v,k){
10970 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
10971 _this.tickItems.splice(k, 1);
10981 this.tickItems.push(r.data);
10986 this.onSelect(r, index);
10988 if(doFocus !== false && !this.blockFocus){
10989 this.inputEl().focus();
10994 restrictHeight : function(){
10995 //this.innerList.dom.style.height = '';
10996 //var inner = this.innerList.dom;
10997 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
10998 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
10999 //this.list.beginUpdate();
11000 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11001 this.list.alignTo(this.inputEl(), this.listAlign);
11002 //this.list.endUpdate();
11006 onEmptyResults : function(){
11011 * Returns true if the dropdown list is expanded, else false.
11013 isExpanded : function(){
11014 return this.list.isVisible();
11018 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11019 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11020 * @param {String} value The data value of the item to select
11021 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11022 * selected item if it is not currently in view (defaults to true)
11023 * @return {Boolean} True if the value matched an item in the list, else false
11025 selectByValue : function(v, scrollIntoView){
11026 if(v !== undefined && v !== null){
11027 var r = this.findRecord(this.valueField || this.displayField, v);
11029 this.select(this.store.indexOf(r), scrollIntoView);
11037 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11038 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11039 * @param {Number} index The zero-based index of the list item to select
11040 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11041 * selected item if it is not currently in view (defaults to true)
11043 select : function(index, scrollIntoView){
11044 this.selectedIndex = index;
11045 this.view.select(index);
11046 if(scrollIntoView !== false){
11047 var el = this.view.getNode(index);
11049 //this.innerList.scrollChildIntoView(el, false);
11056 selectNext : function(){
11057 var ct = this.store.getCount();
11059 if(this.selectedIndex == -1){
11061 }else if(this.selectedIndex < ct-1){
11062 this.select(this.selectedIndex+1);
11068 selectPrev : function(){
11069 var ct = this.store.getCount();
11071 if(this.selectedIndex == -1){
11073 }else if(this.selectedIndex != 0){
11074 this.select(this.selectedIndex-1);
11080 onKeyUp : function(e){
11081 if(this.editable !== false && !e.isSpecialKey()){
11082 this.lastKey = e.getKey();
11083 this.dqTask.delay(this.queryDelay);
11088 validateBlur : function(){
11089 return !this.list || !this.list.isVisible();
11093 initQuery : function(){
11094 this.doQuery(this.getRawValue());
11098 doForce : function(){
11099 if(this.inputEl().dom.value.length > 0){
11100 this.inputEl().dom.value =
11101 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11107 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11108 * query allowing the query action to be canceled if needed.
11109 * @param {String} query The SQL query to execute
11110 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11111 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11112 * saved in the current store (defaults to false)
11114 doQuery : function(q, forceAll){
11116 if(q === undefined || q === null){
11121 forceAll: forceAll,
11125 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11130 forceAll = qe.forceAll;
11131 if(forceAll === true || (q.length >= this.minChars)){
11133 this.hasQuery = true;
11135 if(this.lastQuery != q || this.alwaysQuery){
11136 this.lastQuery = q;
11137 if(this.mode == 'local'){
11138 this.selectedIndex = -1;
11140 this.store.clearFilter();
11142 this.store.filter(this.displayField, q);
11146 this.store.baseParams[this.queryParam] = q;
11148 var options = {params : this.getParams(q)};
11151 options.add = true;
11152 options.params.start = this.page * this.pageSize;
11155 this.store.load(options);
11157 * this code will make the page width larger, at the beginning, the list not align correctly,
11158 * we should expand the list on onLoad
11159 * so command out it
11164 this.selectedIndex = -1;
11169 this.loadNext = false;
11173 getParams : function(q){
11175 //p[this.queryParam] = q;
11179 p.limit = this.pageSize;
11185 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11187 collapse : function(){
11188 if(!this.isExpanded()){
11196 this.cancelBtn.hide();
11197 this.trigger.show();
11200 Roo.get(document).un('mousedown', this.collapseIf, this);
11201 Roo.get(document).un('mousewheel', this.collapseIf, this);
11202 if (!this.editable) {
11203 Roo.get(document).un('keydown', this.listKeyPress, this);
11205 this.fireEvent('collapse', this);
11209 collapseIf : function(e){
11210 var in_combo = e.within(this.el);
11211 var in_list = e.within(this.list);
11213 if (in_combo || in_list) {
11214 //e.stopPropagation();
11219 this.onTickableFooterButtonClick(e, false, false);
11227 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11229 expand : function(){
11231 if(this.isExpanded() || !this.hasFocus){
11235 this.list.alignTo(this.inputEl(), this.listAlign);
11240 this.tickItems = Roo.apply([], this.item);
11243 this.cancelBtn.show();
11244 this.trigger.hide();
11248 Roo.get(document).on('mousedown', this.collapseIf, this);
11249 Roo.get(document).on('mousewheel', this.collapseIf, this);
11250 if (!this.editable) {
11251 Roo.get(document).on('keydown', this.listKeyPress, this);
11254 this.fireEvent('expand', this);
11258 // Implements the default empty TriggerField.onTriggerClick function
11259 onTriggerClick : function()
11261 Roo.log('trigger click');
11268 this.onTickableTriggerClick();
11273 this.loadNext = false;
11275 if(this.isExpanded()){
11277 if (!this.blockFocus) {
11278 this.inputEl().focus();
11282 this.hasFocus = true;
11283 if(this.triggerAction == 'all') {
11284 this.doQuery(this.allQuery, true);
11286 this.doQuery(this.getRawValue());
11288 if (!this.blockFocus) {
11289 this.inputEl().focus();
11294 onTickableTriggerClick : function()
11297 this.loadNext = false;
11298 this.hasFocus = true;
11300 if(this.triggerAction == 'all') {
11301 this.doQuery(this.allQuery, true);
11303 this.doQuery(this.getRawValue());
11307 listKeyPress : function(e)
11309 //Roo.log('listkeypress');
11310 // scroll to first matching element based on key pres..
11311 if (e.isSpecialKey()) {
11314 var k = String.fromCharCode(e.getKey()).toUpperCase();
11317 var csel = this.view.getSelectedNodes();
11318 var cselitem = false;
11320 var ix = this.view.indexOf(csel[0]);
11321 cselitem = this.store.getAt(ix);
11322 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11328 this.store.each(function(v) {
11330 // start at existing selection.
11331 if (cselitem.id == v.id) {
11337 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11338 match = this.store.indexOf(v);
11344 if (match === false) {
11345 return true; // no more action?
11348 this.view.select(match);
11349 var sn = Roo.get(this.view.getSelectedNodes()[0])
11350 //sn.scrollIntoView(sn.dom.parentNode, false);
11353 onViewScroll : function(e, t){
11355 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
11359 this.hasQuery = true;
11361 this.loading = this.list.select('.loading', true).first();
11363 if(this.loading === null){
11364 this.list.createChild({
11366 cls: 'loading select2-more-results select2-active',
11367 html: 'Loading more results...'
11370 this.loading = this.list.select('.loading', true).first();
11372 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11374 this.loading.hide();
11377 this.loading.show();
11382 this.loadNext = true;
11384 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11389 addItem : function(o)
11391 var dv = ''; // display value
11393 if (this.displayField) {
11394 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11396 // this is an error condition!!!
11397 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11404 var choice = this.choices.createChild({
11406 cls: 'select2-search-choice',
11415 cls: 'select2-search-choice-close',
11420 }, this.searchField);
11422 var close = choice.select('a.select2-search-choice-close', true).first()
11424 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11432 this.inputEl().dom.value = '';
11436 onRemoveItem : function(e, _self, o)
11438 e.preventDefault();
11439 var index = this.item.indexOf(o.data) * 1;
11442 Roo.log('not this item?!');
11446 this.item.splice(index, 1);
11451 this.fireEvent('remove', this, e);
11455 syncValue : function()
11457 if(!this.item.length){
11464 Roo.each(this.item, function(i){
11465 if(_this.valueField){
11466 value.push(i[_this.valueField]);
11473 this.value = value.join(',');
11475 if(this.hiddenField){
11476 this.hiddenField.dom.value = this.value;
11480 clearItem : function()
11482 if(!this.multiple){
11488 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11495 inputEl: function ()
11498 return this.searchField;
11500 return this.el.select('input.form-control',true).first();
11504 onTickableFooterButtonClick : function(e, btn, el)
11506 e.preventDefault();
11508 if(btn && btn.name == 'cancel'){
11509 this.tickItems = Roo.apply([], this.item);
11518 Roo.each(this.tickItems, function(o){
11529 * @cfg {Boolean} grow
11533 * @cfg {Number} growMin
11537 * @cfg {Number} growMax
11547 * Ext JS Library 1.1.1
11548 * Copyright(c) 2006-2007, Ext JS, LLC.
11550 * Originally Released Under LGPL - original licence link has changed is not relivant.
11553 * <script type="text/javascript">
11558 * @extends Roo.util.Observable
11559 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11560 * This class also supports single and multi selection modes. <br>
11561 * Create a data model bound view:
11563 var store = new Roo.data.Store(...);
11565 var view = new Roo.View({
11567 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11569 singleSelect: true,
11570 selectedClass: "ydataview-selected",
11574 // listen for node click?
11575 view.on("click", function(vw, index, node, e){
11576 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
11580 dataModel.load("foobar.xml");
11582 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
11584 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
11585 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
11587 * Note: old style constructor is still suported (container, template, config)
11590 * Create a new View
11591 * @param {Object} config The config object
11594 Roo.View = function(config, depreciated_tpl, depreciated_config){
11596 this.parent = false;
11598 if (typeof(depreciated_tpl) == 'undefined') {
11599 // new way.. - universal constructor.
11600 Roo.apply(this, config);
11601 this.el = Roo.get(this.el);
11604 this.el = Roo.get(config);
11605 this.tpl = depreciated_tpl;
11606 Roo.apply(this, depreciated_config);
11608 this.wrapEl = this.el.wrap().wrap();
11609 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
11612 if(typeof(this.tpl) == "string"){
11613 this.tpl = new Roo.Template(this.tpl);
11615 // support xtype ctors..
11616 this.tpl = new Roo.factory(this.tpl, Roo);
11620 this.tpl.compile();
11625 * @event beforeclick
11626 * Fires before a click is processed. Returns false to cancel the default action.
11627 * @param {Roo.View} this
11628 * @param {Number} index The index of the target node
11629 * @param {HTMLElement} node The target node
11630 * @param {Roo.EventObject} e The raw event object
11632 "beforeclick" : true,
11635 * Fires when a template node is clicked.
11636 * @param {Roo.View} this
11637 * @param {Number} index The index of the target node
11638 * @param {HTMLElement} node The target node
11639 * @param {Roo.EventObject} e The raw event object
11644 * Fires when a template node is double clicked.
11645 * @param {Roo.View} this
11646 * @param {Number} index The index of the target node
11647 * @param {HTMLElement} node The target node
11648 * @param {Roo.EventObject} e The raw event object
11652 * @event contextmenu
11653 * Fires when a template node is right clicked.
11654 * @param {Roo.View} this
11655 * @param {Number} index The index of the target node
11656 * @param {HTMLElement} node The target node
11657 * @param {Roo.EventObject} e The raw event object
11659 "contextmenu" : true,
11661 * @event selectionchange
11662 * Fires when the selected nodes change.
11663 * @param {Roo.View} this
11664 * @param {Array} selections Array of the selected nodes
11666 "selectionchange" : true,
11669 * @event beforeselect
11670 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
11671 * @param {Roo.View} this
11672 * @param {HTMLElement} node The node to be selected
11673 * @param {Array} selections Array of currently selected nodes
11675 "beforeselect" : true,
11677 * @event preparedata
11678 * Fires on every row to render, to allow you to change the data.
11679 * @param {Roo.View} this
11680 * @param {Object} data to be rendered (change this)
11682 "preparedata" : true
11690 "click": this.onClick,
11691 "dblclick": this.onDblClick,
11692 "contextmenu": this.onContextMenu,
11696 this.selections = [];
11698 this.cmp = new Roo.CompositeElementLite([]);
11700 this.store = Roo.factory(this.store, Roo.data);
11701 this.setStore(this.store, true);
11704 if ( this.footer && this.footer.xtype) {
11706 var fctr = this.wrapEl.appendChild(document.createElement("div"));
11708 this.footer.dataSource = this.store
11709 this.footer.container = fctr;
11710 this.footer = Roo.factory(this.footer, Roo);
11711 fctr.insertFirst(this.el);
11713 // this is a bit insane - as the paging toolbar seems to detach the el..
11714 // dom.parentNode.parentNode.parentNode
11715 // they get detached?
11719 Roo.View.superclass.constructor.call(this);
11724 Roo.extend(Roo.View, Roo.util.Observable, {
11727 * @cfg {Roo.data.Store} store Data store to load data from.
11732 * @cfg {String|Roo.Element} el The container element.
11737 * @cfg {String|Roo.Template} tpl The template used by this View
11741 * @cfg {String} dataName the named area of the template to use as the data area
11742 * Works with domtemplates roo-name="name"
11746 * @cfg {String} selectedClass The css class to add to selected nodes
11748 selectedClass : "x-view-selected",
11750 * @cfg {String} emptyText The empty text to show when nothing is loaded.
11755 * @cfg {String} text to display on mask (default Loading)
11759 * @cfg {Boolean} multiSelect Allow multiple selection
11761 multiSelect : false,
11763 * @cfg {Boolean} singleSelect Allow single selection
11765 singleSelect: false,
11768 * @cfg {Boolean} toggleSelect - selecting
11770 toggleSelect : false,
11773 * @cfg {Boolean} tickable - selecting
11778 * Returns the element this view is bound to.
11779 * @return {Roo.Element}
11781 getEl : function(){
11782 return this.wrapEl;
11788 * Refreshes the view. - called by datachanged on the store. - do not call directly.
11790 refresh : function(){
11791 Roo.log('refresh');
11794 // if we are using something like 'domtemplate', then
11795 // the what gets used is:
11796 // t.applySubtemplate(NAME, data, wrapping data..)
11797 // the outer template then get' applied with
11798 // the store 'extra data'
11799 // and the body get's added to the
11800 // roo-name="data" node?
11801 // <span class='roo-tpl-{name}'></span> ?????
11805 this.clearSelections();
11806 this.el.update("");
11808 var records = this.store.getRange();
11809 if(records.length < 1) {
11811 // is this valid?? = should it render a template??
11813 this.el.update(this.emptyText);
11817 if (this.dataName) {
11818 this.el.update(t.apply(this.store.meta)); //????
11819 el = this.el.child('.roo-tpl-' + this.dataName);
11822 for(var i = 0, len = records.length; i < len; i++){
11823 var data = this.prepareData(records[i].data, i, records[i]);
11824 this.fireEvent("preparedata", this, data, i, records[i]);
11826 var d = Roo.apply({}, data);
11829 Roo.apply(d, {'roo-id' : Roo.id()});
11833 Roo.each(this.parent.item, function(item){
11834 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
11837 Roo.apply(d, {'roo-data-checked' : 'checked'});
11841 html[html.length] = Roo.util.Format.trim(
11843 t.applySubtemplate(this.dataName, d, this.store.meta) :
11850 el.update(html.join(""));
11851 this.nodes = el.dom.childNodes;
11852 this.updateIndexes(0);
11857 * Function to override to reformat the data that is sent to
11858 * the template for each node.
11859 * DEPRICATED - use the preparedata event handler.
11860 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
11861 * a JSON object for an UpdateManager bound view).
11863 prepareData : function(data, index, record)
11865 this.fireEvent("preparedata", this, data, index, record);
11869 onUpdate : function(ds, record){
11870 Roo.log('on update');
11871 this.clearSelections();
11872 var index = this.store.indexOf(record);
11873 var n = this.nodes[index];
11874 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
11875 n.parentNode.removeChild(n);
11876 this.updateIndexes(index, index);
11882 onAdd : function(ds, records, index)
11884 Roo.log(['on Add', ds, records, index] );
11885 this.clearSelections();
11886 if(this.nodes.length == 0){
11890 var n = this.nodes[index];
11891 for(var i = 0, len = records.length; i < len; i++){
11892 var d = this.prepareData(records[i].data, i, records[i]);
11894 this.tpl.insertBefore(n, d);
11897 this.tpl.append(this.el, d);
11900 this.updateIndexes(index);
11903 onRemove : function(ds, record, index){
11904 Roo.log('onRemove');
11905 this.clearSelections();
11906 var el = this.dataName ?
11907 this.el.child('.roo-tpl-' + this.dataName) :
11910 el.dom.removeChild(this.nodes[index]);
11911 this.updateIndexes(index);
11915 * Refresh an individual node.
11916 * @param {Number} index
11918 refreshNode : function(index){
11919 this.onUpdate(this.store, this.store.getAt(index));
11922 updateIndexes : function(startIndex, endIndex){
11923 var ns = this.nodes;
11924 startIndex = startIndex || 0;
11925 endIndex = endIndex || ns.length - 1;
11926 for(var i = startIndex; i <= endIndex; i++){
11927 ns[i].nodeIndex = i;
11932 * Changes the data store this view uses and refresh the view.
11933 * @param {Store} store
11935 setStore : function(store, initial){
11936 if(!initial && this.store){
11937 this.store.un("datachanged", this.refresh);
11938 this.store.un("add", this.onAdd);
11939 this.store.un("remove", this.onRemove);
11940 this.store.un("update", this.onUpdate);
11941 this.store.un("clear", this.refresh);
11942 this.store.un("beforeload", this.onBeforeLoad);
11943 this.store.un("load", this.onLoad);
11944 this.store.un("loadexception", this.onLoad);
11948 store.on("datachanged", this.refresh, this);
11949 store.on("add", this.onAdd, this);
11950 store.on("remove", this.onRemove, this);
11951 store.on("update", this.onUpdate, this);
11952 store.on("clear", this.refresh, this);
11953 store.on("beforeload", this.onBeforeLoad, this);
11954 store.on("load", this.onLoad, this);
11955 store.on("loadexception", this.onLoad, this);
11963 * onbeforeLoad - masks the loading area.
11966 onBeforeLoad : function(store,opts)
11968 Roo.log('onBeforeLoad');
11970 this.el.update("");
11972 this.el.mask(this.mask ? this.mask : "Loading" );
11974 onLoad : function ()
11981 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
11982 * @param {HTMLElement} node
11983 * @return {HTMLElement} The template node
11985 findItemFromChild : function(node){
11986 var el = this.dataName ?
11987 this.el.child('.roo-tpl-' + this.dataName,true) :
11990 if(!node || node.parentNode == el){
11993 var p = node.parentNode;
11994 while(p && p != el){
11995 if(p.parentNode == el){
12004 onClick : function(e){
12005 var item = this.findItemFromChild(e.getTarget());
12007 var index = this.indexOf(item);
12008 if(this.onItemClick(item, index, e) !== false){
12009 this.fireEvent("click", this, index, item, e);
12012 this.clearSelections();
12017 onContextMenu : function(e){
12018 var item = this.findItemFromChild(e.getTarget());
12020 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12025 onDblClick : function(e){
12026 var item = this.findItemFromChild(e.getTarget());
12028 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12032 onItemClick : function(item, index, e)
12034 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12037 if (this.toggleSelect) {
12038 var m = this.isSelected(item) ? 'unselect' : 'select';
12041 _t[m](item, true, false);
12044 if(this.multiSelect || this.singleSelect){
12045 if(this.multiSelect && e.shiftKey && this.lastSelection){
12046 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12048 this.select(item, this.multiSelect && e.ctrlKey);
12049 this.lastSelection = item;
12052 if(!this.tickable){
12053 e.preventDefault();
12061 * Get the number of selected nodes.
12064 getSelectionCount : function(){
12065 return this.selections.length;
12069 * Get the currently selected nodes.
12070 * @return {Array} An array of HTMLElements
12072 getSelectedNodes : function(){
12073 return this.selections;
12077 * Get the indexes of the selected nodes.
12080 getSelectedIndexes : function(){
12081 var indexes = [], s = this.selections;
12082 for(var i = 0, len = s.length; i < len; i++){
12083 indexes.push(s[i].nodeIndex);
12089 * Clear all selections
12090 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12092 clearSelections : function(suppressEvent){
12093 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12094 this.cmp.elements = this.selections;
12095 this.cmp.removeClass(this.selectedClass);
12096 this.selections = [];
12097 if(!suppressEvent){
12098 this.fireEvent("selectionchange", this, this.selections);
12104 * Returns true if the passed node is selected
12105 * @param {HTMLElement/Number} node The node or node index
12106 * @return {Boolean}
12108 isSelected : function(node){
12109 var s = this.selections;
12113 node = this.getNode(node);
12114 return s.indexOf(node) !== -1;
12119 * @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
12120 * @param {Boolean} keepExisting (optional) true to keep existing selections
12121 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12123 select : function(nodeInfo, keepExisting, suppressEvent){
12124 if(nodeInfo instanceof Array){
12126 this.clearSelections(true);
12128 for(var i = 0, len = nodeInfo.length; i < len; i++){
12129 this.select(nodeInfo[i], true, true);
12133 var node = this.getNode(nodeInfo);
12134 if(!node || this.isSelected(node)){
12135 return; // already selected.
12138 this.clearSelections(true);
12140 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12141 Roo.fly(node).addClass(this.selectedClass);
12142 this.selections.push(node);
12143 if(!suppressEvent){
12144 this.fireEvent("selectionchange", this, this.selections);
12152 * @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
12153 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12154 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12156 unselect : function(nodeInfo, keepExisting, suppressEvent)
12158 if(nodeInfo instanceof Array){
12159 Roo.each(this.selections, function(s) {
12160 this.unselect(s, nodeInfo);
12164 var node = this.getNode(nodeInfo);
12165 if(!node || !this.isSelected(node)){
12166 Roo.log("not selected");
12167 return; // not selected.
12171 Roo.each(this.selections, function(s) {
12173 Roo.fly(node).removeClass(this.selectedClass);
12180 this.selections= ns;
12181 this.fireEvent("selectionchange", this, this.selections);
12185 * Gets a template node.
12186 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12187 * @return {HTMLElement} The node or null if it wasn't found
12189 getNode : function(nodeInfo){
12190 if(typeof nodeInfo == "string"){
12191 return document.getElementById(nodeInfo);
12192 }else if(typeof nodeInfo == "number"){
12193 return this.nodes[nodeInfo];
12199 * Gets a range template nodes.
12200 * @param {Number} startIndex
12201 * @param {Number} endIndex
12202 * @return {Array} An array of nodes
12204 getNodes : function(start, end){
12205 var ns = this.nodes;
12206 start = start || 0;
12207 end = typeof end == "undefined" ? ns.length - 1 : end;
12210 for(var i = start; i <= end; i++){
12214 for(var i = start; i >= end; i--){
12222 * Finds the index of the passed node
12223 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12224 * @return {Number} The index of the node or -1
12226 indexOf : function(node){
12227 node = this.getNode(node);
12228 if(typeof node.nodeIndex == "number"){
12229 return node.nodeIndex;
12231 var ns = this.nodes;
12232 for(var i = 0, len = ns.length; i < len; i++){
12243 * based on jquery fullcalendar
12247 Roo.bootstrap = Roo.bootstrap || {};
12249 * @class Roo.bootstrap.Calendar
12250 * @extends Roo.bootstrap.Component
12251 * Bootstrap Calendar class
12252 * @cfg {Boolean} loadMask (true|false) default false
12253 * @cfg {Object} header generate the user specific header of the calendar, default false
12256 * Create a new Container
12257 * @param {Object} config The config object
12262 Roo.bootstrap.Calendar = function(config){
12263 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12267 * Fires when a date is selected
12268 * @param {DatePicker} this
12269 * @param {Date} date The selected date
12273 * @event monthchange
12274 * Fires when the displayed month changes
12275 * @param {DatePicker} this
12276 * @param {Date} date The selected month
12278 'monthchange': true,
12280 * @event evententer
12281 * Fires when mouse over an event
12282 * @param {Calendar} this
12283 * @param {event} Event
12285 'evententer': true,
12287 * @event eventleave
12288 * Fires when the mouse leaves an
12289 * @param {Calendar} this
12292 'eventleave': true,
12294 * @event eventclick
12295 * Fires when the mouse click an
12296 * @param {Calendar} this
12305 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12308 * @cfg {Number} startDay
12309 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12317 getAutoCreate : function(){
12320 var fc_button = function(name, corner, style, content ) {
12321 return Roo.apply({},{
12323 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12325 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12328 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12339 style : 'width:100%',
12346 cls : 'fc-header-left',
12348 fc_button('prev', 'left', 'arrow', '‹' ),
12349 fc_button('next', 'right', 'arrow', '›' ),
12350 { tag: 'span', cls: 'fc-header-space' },
12351 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12359 cls : 'fc-header-center',
12363 cls: 'fc-header-title',
12366 html : 'month / year'
12374 cls : 'fc-header-right',
12376 /* fc_button('month', 'left', '', 'month' ),
12377 fc_button('week', '', '', 'week' ),
12378 fc_button('day', 'right', '', 'day' )
12390 header = this.header;
12393 var cal_heads = function() {
12395 // fixme - handle this.
12397 for (var i =0; i < Date.dayNames.length; i++) {
12398 var d = Date.dayNames[i];
12401 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12402 html : d.substring(0,3)
12406 ret[0].cls += ' fc-first';
12407 ret[6].cls += ' fc-last';
12410 var cal_cell = function(n) {
12413 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12418 cls: 'fc-day-number',
12422 cls: 'fc-day-content',
12426 style: 'position: relative;' // height: 17px;
12438 var cal_rows = function() {
12441 for (var r = 0; r < 6; r++) {
12448 for (var i =0; i < Date.dayNames.length; i++) {
12449 var d = Date.dayNames[i];
12450 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12453 row.cn[0].cls+=' fc-first';
12454 row.cn[0].cn[0].style = 'min-height:90px';
12455 row.cn[6].cls+=' fc-last';
12459 ret[0].cls += ' fc-first';
12460 ret[4].cls += ' fc-prev-last';
12461 ret[5].cls += ' fc-last';
12468 cls: 'fc-border-separate',
12469 style : 'width:100%',
12477 cls : 'fc-first fc-last',
12495 cls : 'fc-content',
12496 style : "position: relative;",
12499 cls : 'fc-view fc-view-month fc-grid',
12500 style : 'position: relative',
12501 unselectable : 'on',
12504 cls : 'fc-event-container',
12505 style : 'position:absolute;z-index:8;top:0;left:0;'
12523 initEvents : function()
12526 throw "can not find store for calendar";
12532 style: "text-align:center",
12536 style: "background-color:white;width:50%;margin:250 auto",
12540 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12551 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12553 var size = this.el.select('.fc-content', true).first().getSize();
12554 this.maskEl.setSize(size.width, size.height);
12555 this.maskEl.enableDisplayMode("block");
12556 if(!this.loadMask){
12557 this.maskEl.hide();
12560 this.store = Roo.factory(this.store, Roo.data);
12561 this.store.on('load', this.onLoad, this);
12562 this.store.on('beforeload', this.onBeforeLoad, this);
12566 this.cells = this.el.select('.fc-day',true);
12567 //Roo.log(this.cells);
12568 this.textNodes = this.el.query('.fc-day-number');
12569 this.cells.addClassOnOver('fc-state-hover');
12571 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12572 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12573 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12574 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12576 this.on('monthchange', this.onMonthChange, this);
12578 this.update(new Date().clearTime());
12581 resize : function() {
12582 var sz = this.el.getSize();
12584 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
12585 this.el.select('.fc-day-content div',true).setHeight(34);
12590 showPrevMonth : function(e){
12591 this.update(this.activeDate.add("mo", -1));
12593 showToday : function(e){
12594 this.update(new Date().clearTime());
12597 showNextMonth : function(e){
12598 this.update(this.activeDate.add("mo", 1));
12602 showPrevYear : function(){
12603 this.update(this.activeDate.add("y", -1));
12607 showNextYear : function(){
12608 this.update(this.activeDate.add("y", 1));
12613 update : function(date)
12615 var vd = this.activeDate;
12616 this.activeDate = date;
12617 // if(vd && this.el){
12618 // var t = date.getTime();
12619 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
12620 // Roo.log('using add remove');
12622 // this.fireEvent('monthchange', this, date);
12624 // this.cells.removeClass("fc-state-highlight");
12625 // this.cells.each(function(c){
12626 // if(c.dateValue == t){
12627 // c.addClass("fc-state-highlight");
12628 // setTimeout(function(){
12629 // try{c.dom.firstChild.focus();}catch(e){}
12639 var days = date.getDaysInMonth();
12641 var firstOfMonth = date.getFirstDateOfMonth();
12642 var startingPos = firstOfMonth.getDay()-this.startDay;
12644 if(startingPos < this.startDay){
12648 var pm = date.add(Date.MONTH, -1);
12649 var prevStart = pm.getDaysInMonth()-startingPos;
12651 this.cells = this.el.select('.fc-day',true);
12652 this.textNodes = this.el.query('.fc-day-number');
12653 this.cells.addClassOnOver('fc-state-hover');
12655 var cells = this.cells.elements;
12656 var textEls = this.textNodes;
12658 Roo.each(cells, function(cell){
12659 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
12662 days += startingPos;
12664 // convert everything to numbers so it's fast
12665 var day = 86400000;
12666 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
12669 //Roo.log(prevStart);
12671 var today = new Date().clearTime().getTime();
12672 var sel = date.clearTime().getTime();
12673 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
12674 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
12675 var ddMatch = this.disabledDatesRE;
12676 var ddText = this.disabledDatesText;
12677 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
12678 var ddaysText = this.disabledDaysText;
12679 var format = this.format;
12681 var setCellClass = function(cal, cell){
12685 //Roo.log('set Cell Class');
12687 var t = d.getTime();
12691 cell.dateValue = t;
12693 cell.className += " fc-today";
12694 cell.className += " fc-state-highlight";
12695 cell.title = cal.todayText;
12698 // disable highlight in other month..
12699 //cell.className += " fc-state-highlight";
12704 cell.className = " fc-state-disabled";
12705 cell.title = cal.minText;
12709 cell.className = " fc-state-disabled";
12710 cell.title = cal.maxText;
12714 if(ddays.indexOf(d.getDay()) != -1){
12715 cell.title = ddaysText;
12716 cell.className = " fc-state-disabled";
12719 if(ddMatch && format){
12720 var fvalue = d.dateFormat(format);
12721 if(ddMatch.test(fvalue)){
12722 cell.title = ddText.replace("%0", fvalue);
12723 cell.className = " fc-state-disabled";
12727 if (!cell.initialClassName) {
12728 cell.initialClassName = cell.dom.className;
12731 cell.dom.className = cell.initialClassName + ' ' + cell.className;
12736 for(; i < startingPos; i++) {
12737 textEls[i].innerHTML = (++prevStart);
12738 d.setDate(d.getDate()+1);
12740 cells[i].className = "fc-past fc-other-month";
12741 setCellClass(this, cells[i]);
12746 for(; i < days; i++){
12747 intDay = i - startingPos + 1;
12748 textEls[i].innerHTML = (intDay);
12749 d.setDate(d.getDate()+1);
12751 cells[i].className = ''; // "x-date-active";
12752 setCellClass(this, cells[i]);
12756 for(; i < 42; i++) {
12757 textEls[i].innerHTML = (++extraDays);
12758 d.setDate(d.getDate()+1);
12760 cells[i].className = "fc-future fc-other-month";
12761 setCellClass(this, cells[i]);
12764 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
12766 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
12768 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
12769 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
12771 if(totalRows != 6){
12772 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
12773 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
12776 this.fireEvent('monthchange', this, date);
12780 if(!this.internalRender){
12781 var main = this.el.dom.firstChild;
12782 var w = main.offsetWidth;
12783 this.el.setWidth(w + this.el.getBorderWidth("lr"));
12784 Roo.fly(main).setWidth(w);
12785 this.internalRender = true;
12786 // opera does not respect the auto grow header center column
12787 // then, after it gets a width opera refuses to recalculate
12788 // without a second pass
12789 if(Roo.isOpera && !this.secondPass){
12790 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
12791 this.secondPass = true;
12792 this.update.defer(10, this, [date]);
12799 findCell : function(dt) {
12800 dt = dt.clearTime().getTime();
12802 this.cells.each(function(c){
12803 //Roo.log("check " +c.dateValue + '?=' + dt);
12804 if(c.dateValue == dt){
12814 findCells : function(ev) {
12815 var s = ev.start.clone().clearTime().getTime();
12817 var e= ev.end.clone().clearTime().getTime();
12820 this.cells.each(function(c){
12821 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
12823 if(c.dateValue > e){
12826 if(c.dateValue < s){
12835 // findBestRow: function(cells)
12839 // for (var i =0 ; i < cells.length;i++) {
12840 // ret = Math.max(cells[i].rows || 0,ret);
12847 addItem : function(ev)
12849 // look for vertical location slot in
12850 var cells = this.findCells(ev);
12852 // ev.row = this.findBestRow(cells);
12854 // work out the location.
12858 for(var i =0; i < cells.length; i++) {
12860 cells[i].row = cells[0].row;
12863 cells[i].row = cells[i].row + 1;
12873 if (crow.start.getY() == cells[i].getY()) {
12875 crow.end = cells[i];
12892 cells[0].events.push(ev);
12894 this.calevents.push(ev);
12897 clearEvents: function() {
12899 if(!this.calevents){
12903 Roo.each(this.cells.elements, function(c){
12909 Roo.each(this.calevents, function(e) {
12910 Roo.each(e.els, function(el) {
12911 el.un('mouseenter' ,this.onEventEnter, this);
12912 el.un('mouseleave' ,this.onEventLeave, this);
12917 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
12923 renderEvents: function()
12927 this.cells.each(function(c) {
12936 if(c.row != c.events.length){
12937 r = 4 - (4 - (c.row - c.events.length));
12940 c.events = ev.slice(0, r);
12941 c.more = ev.slice(r);
12943 if(c.more.length && c.more.length == 1){
12944 c.events.push(c.more.pop());
12947 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
12951 this.cells.each(function(c) {
12953 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
12956 for (var e = 0; e < c.events.length; e++){
12957 var ev = c.events[e];
12958 var rows = ev.rows;
12960 for(var i = 0; i < rows.length; i++) {
12962 // how many rows should it span..
12965 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
12966 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
12968 unselectable : "on",
12971 cls: 'fc-event-inner',
12975 // cls: 'fc-event-time',
12976 // html : cells.length > 1 ? '' : ev.time
12980 cls: 'fc-event-title',
12981 html : String.format('{0}', ev.title)
12988 cls: 'ui-resizable-handle ui-resizable-e',
12989 html : '  '
12996 cfg.cls += ' fc-event-start';
12998 if ((i+1) == rows.length) {
12999 cfg.cls += ' fc-event-end';
13002 var ctr = _this.el.select('.fc-event-container',true).first();
13003 var cg = ctr.createChild(cfg);
13005 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13006 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13008 var r = (c.more.length) ? 1 : 0;
13009 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13010 cg.setWidth(ebox.right - sbox.x -2);
13012 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13013 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13014 cg.on('click', _this.onEventClick, _this, ev);
13025 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13026 style : 'position: absolute',
13027 unselectable : "on",
13030 cls: 'fc-event-inner',
13034 cls: 'fc-event-title',
13042 cls: 'ui-resizable-handle ui-resizable-e',
13043 html : '  '
13049 var ctr = _this.el.select('.fc-event-container',true).first();
13050 var cg = ctr.createChild(cfg);
13052 var sbox = c.select('.fc-day-content',true).first().getBox();
13053 var ebox = c.select('.fc-day-content',true).first().getBox();
13055 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13056 cg.setWidth(ebox.right - sbox.x -2);
13058 cg.on('click', _this.onMoreEventClick, _this, c.more);
13068 onEventEnter: function (e, el,event,d) {
13069 this.fireEvent('evententer', this, el, event);
13072 onEventLeave: function (e, el,event,d) {
13073 this.fireEvent('eventleave', this, el, event);
13076 onEventClick: function (e, el,event,d) {
13077 this.fireEvent('eventclick', this, el, event);
13080 onMonthChange: function () {
13084 onMoreEventClick: function(e, el, more)
13088 this.calpopover.placement = 'right';
13089 this.calpopover.setTitle('More');
13091 this.calpopover.setContent('');
13093 var ctr = this.calpopover.el.select('.popover-content', true).first();
13095 Roo.each(more, function(m){
13097 cls : 'fc-event-hori fc-event-draggable',
13100 var cg = ctr.createChild(cfg);
13102 cg.on('click', _this.onEventClick, _this, m);
13105 this.calpopover.show(el);
13110 onLoad: function ()
13112 this.calevents = [];
13115 if(this.store.getCount() > 0){
13116 this.store.data.each(function(d){
13119 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13120 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13121 time : d.data.start_time,
13122 title : d.data.title,
13123 description : d.data.description,
13124 venue : d.data.venue
13129 this.renderEvents();
13131 if(this.calevents.length && this.loadMask){
13132 this.maskEl.hide();
13136 onBeforeLoad: function()
13138 this.clearEvents();
13140 this.maskEl.show();
13154 * @class Roo.bootstrap.Popover
13155 * @extends Roo.bootstrap.Component
13156 * Bootstrap Popover class
13157 * @cfg {String} html contents of the popover (or false to use children..)
13158 * @cfg {String} title of popover (or false to hide)
13159 * @cfg {String} placement how it is placed
13160 * @cfg {String} trigger click || hover (or false to trigger manually)
13161 * @cfg {String} over what (parent or false to trigger manually.)
13164 * Create a new Popover
13165 * @param {Object} config The config object
13168 Roo.bootstrap.Popover = function(config){
13169 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13172 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13174 title: 'Fill in a title',
13177 placement : 'right',
13178 trigger : 'hover', // hover
13182 can_build_overlaid : false,
13184 getChildContainer : function()
13186 return this.el.select('.popover-content',true).first();
13189 getAutoCreate : function(){
13190 Roo.log('make popover?');
13192 cls : 'popover roo-dynamic',
13193 style: 'display:block',
13199 cls : 'popover-inner',
13203 cls: 'popover-title',
13207 cls : 'popover-content',
13218 setTitle: function(str)
13220 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13222 setContent: function(str)
13224 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13226 // as it get's added to the bottom of the page.
13227 onRender : function(ct, position)
13229 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13231 var cfg = Roo.apply({}, this.getAutoCreate());
13235 cfg.cls += ' ' + this.cls;
13238 cfg.style = this.style;
13240 Roo.log("adding to ")
13241 this.el = Roo.get(document.body).createChild(cfg, position);
13247 initEvents : function()
13249 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13250 this.el.enableDisplayMode('block');
13252 if (this.over === false) {
13255 if (this.triggers === false) {
13258 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13259 var triggers = this.trigger ? this.trigger.split(' ') : [];
13260 Roo.each(triggers, function(trigger) {
13262 if (trigger == 'click') {
13263 on_el.on('click', this.toggle, this);
13264 } else if (trigger != 'manual') {
13265 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13266 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13268 on_el.on(eventIn ,this.enter, this);
13269 on_el.on(eventOut, this.leave, this);
13280 toggle : function () {
13281 this.hoverState == 'in' ? this.leave() : this.enter();
13284 enter : function () {
13287 clearTimeout(this.timeout);
13289 this.hoverState = 'in'
13291 if (!this.delay || !this.delay.show) {
13296 this.timeout = setTimeout(function () {
13297 if (_t.hoverState == 'in') {
13300 }, this.delay.show)
13302 leave : function() {
13303 clearTimeout(this.timeout);
13305 this.hoverState = 'out'
13307 if (!this.delay || !this.delay.hide) {
13312 this.timeout = setTimeout(function () {
13313 if (_t.hoverState == 'out') {
13316 }, this.delay.hide)
13319 show : function (on_el)
13322 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13325 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13326 if (this.html !== false) {
13327 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13329 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13330 if (!this.title.length) {
13331 this.el.select('.popover-title',true).hide();
13334 var placement = typeof this.placement == 'function' ?
13335 this.placement.call(this, this.el, on_el) :
13338 var autoToken = /\s?auto?\s?/i;
13339 var autoPlace = autoToken.test(placement);
13341 placement = placement.replace(autoToken, '') || 'top';
13345 //this.el.setXY([0,0]);
13347 this.el.dom.style.display='block';
13348 this.el.addClass(placement);
13350 //this.el.appendTo(on_el);
13352 var p = this.getPosition();
13353 var box = this.el.getBox();
13358 var align = Roo.bootstrap.Popover.alignment[placement]
13359 this.el.alignTo(on_el, align[0],align[1]);
13360 //var arrow = this.el.select('.arrow',true).first();
13361 //arrow.set(align[2],
13363 this.el.addClass('in');
13364 this.hoverState = null;
13366 if (this.el.hasClass('fade')) {
13373 this.el.setXY([0,0]);
13374 this.el.removeClass('in');
13381 Roo.bootstrap.Popover.alignment = {
13382 'left' : ['r-l', [-10,0], 'right'],
13383 'right' : ['l-r', [10,0], 'left'],
13384 'bottom' : ['t-b', [0,10], 'top'],
13385 'top' : [ 'b-t', [0,-10], 'bottom']
13396 * @class Roo.bootstrap.Progress
13397 * @extends Roo.bootstrap.Component
13398 * Bootstrap Progress class
13399 * @cfg {Boolean} striped striped of the progress bar
13400 * @cfg {Boolean} active animated of the progress bar
13404 * Create a new Progress
13405 * @param {Object} config The config object
13408 Roo.bootstrap.Progress = function(config){
13409 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13412 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13417 getAutoCreate : function(){
13425 cfg.cls += ' progress-striped';
13429 cfg.cls += ' active';
13448 * @class Roo.bootstrap.ProgressBar
13449 * @extends Roo.bootstrap.Component
13450 * Bootstrap ProgressBar class
13451 * @cfg {Number} aria_valuenow aria-value now
13452 * @cfg {Number} aria_valuemin aria-value min
13453 * @cfg {Number} aria_valuemax aria-value max
13454 * @cfg {String} label label for the progress bar
13455 * @cfg {String} panel (success | info | warning | danger )
13456 * @cfg {String} role role of the progress bar
13457 * @cfg {String} sr_only text
13461 * Create a new ProgressBar
13462 * @param {Object} config The config object
13465 Roo.bootstrap.ProgressBar = function(config){
13466 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13469 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13473 aria_valuemax : 100,
13479 getAutoCreate : function()
13484 cls: 'progress-bar',
13485 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13497 cfg.role = this.role;
13500 if(this.aria_valuenow){
13501 cfg['aria-valuenow'] = this.aria_valuenow;
13504 if(this.aria_valuemin){
13505 cfg['aria-valuemin'] = this.aria_valuemin;
13508 if(this.aria_valuemax){
13509 cfg['aria-valuemax'] = this.aria_valuemax;
13512 if(this.label && !this.sr_only){
13513 cfg.html = this.label;
13517 cfg.cls += ' progress-bar-' + this.panel;
13523 update : function(aria_valuenow)
13525 this.aria_valuenow = aria_valuenow;
13527 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13542 * @class Roo.bootstrap.TabPanel
13543 * @extends Roo.bootstrap.Component
13544 * Bootstrap TabPanel class
13545 * @cfg {Boolean} active panel active
13546 * @cfg {String} html panel content
13547 * @cfg {String} tabId tab relate id
13548 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
13552 * Create a new TabPanel
13553 * @param {Object} config The config object
13556 Roo.bootstrap.TabPanel = function(config){
13557 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
13561 * Fires when the active status changes
13562 * @param {Roo.bootstrap.TabPanel} this
13563 * @param {Boolean} state the new state
13570 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
13577 getAutoCreate : function(){
13581 html: this.html || ''
13585 cfg.cls += ' active';
13589 cfg.tabId = this.tabId;
13594 onRender : function(ct, position)
13596 // Roo.log("Call onRender: " + this.xtype);
13598 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
13600 if (this.navId && this.tabId) {
13601 var item = Roo.bootstrap.NavGroup.get(this.navId).getNavItem(this.tabId);
13603 Roo.log("could not find navID:" + this.navId + ", tabId: " + this.tabId);
13605 item.on('changed', function(item, state) {
13606 this.setActive(state);
13612 setActive: function(state)
13614 Roo.log("panel - set active " + this.tabId + "=" + state);
13616 this.active = state;
13618 this.el.removeClass('active');
13620 } else if (!this.el.hasClass('active')) {
13621 this.el.addClass('active');
13623 this.fireEvent('changed', this, state);
13640 * @class Roo.bootstrap.DateField
13641 * @extends Roo.bootstrap.Input
13642 * Bootstrap DateField class
13643 * @cfg {Number} weekStart default 0
13644 * @cfg {Number} weekStart default 0
13645 * @cfg {Number} viewMode default empty, (months|years)
13646 * @cfg {Number} minViewMode default empty, (months|years)
13647 * @cfg {Number} startDate default -Infinity
13648 * @cfg {Number} endDate default Infinity
13649 * @cfg {Boolean} todayHighlight default false
13650 * @cfg {Boolean} todayBtn default false
13651 * @cfg {Boolean} calendarWeeks default false
13652 * @cfg {Object} daysOfWeekDisabled default empty
13654 * @cfg {Boolean} keyboardNavigation default true
13655 * @cfg {String} language default en
13658 * Create a new DateField
13659 * @param {Object} config The config object
13662 Roo.bootstrap.DateField = function(config){
13663 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
13667 * Fires when this field show.
13668 * @param {Roo.bootstrap.DateField} this
13669 * @param {Mixed} date The date value
13674 * Fires when this field hide.
13675 * @param {Roo.bootstrap.DateField} this
13676 * @param {Mixed} date The date value
13681 * Fires when select a date.
13682 * @param {Roo.bootstrap.DateField} this
13683 * @param {Mixed} date The date value
13689 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
13692 * @cfg {String} format
13693 * The default date format string which can be overriden for localization support. The format must be
13694 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
13698 * @cfg {String} altFormats
13699 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
13700 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
13702 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
13710 todayHighlight : false,
13716 keyboardNavigation: true,
13718 calendarWeeks: false,
13720 startDate: -Infinity,
13724 daysOfWeekDisabled: [],
13728 UTCDate: function()
13730 return new Date(Date.UTC.apply(Date, arguments));
13733 UTCToday: function()
13735 var today = new Date();
13736 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
13739 getDate: function() {
13740 var d = this.getUTCDate();
13741 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
13744 getUTCDate: function() {
13748 setDate: function(d) {
13749 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
13752 setUTCDate: function(d) {
13754 this.setValue(this.formatDate(this.date));
13757 onRender: function(ct, position)
13760 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
13762 this.language = this.language || 'en';
13763 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
13764 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
13766 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
13767 this.format = this.format || 'm/d/y';
13768 this.isInline = false;
13769 this.isInput = true;
13770 this.component = this.el.select('.add-on', true).first() || false;
13771 this.component = (this.component && this.component.length === 0) ? false : this.component;
13772 this.hasInput = this.component && this.inputEL().length;
13774 if (typeof(this.minViewMode === 'string')) {
13775 switch (this.minViewMode) {
13777 this.minViewMode = 1;
13780 this.minViewMode = 2;
13783 this.minViewMode = 0;
13788 if (typeof(this.viewMode === 'string')) {
13789 switch (this.viewMode) {
13802 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
13804 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13806 this.picker().on('mousedown', this.onMousedown, this);
13807 this.picker().on('click', this.onClick, this);
13809 this.picker().addClass('datepicker-dropdown');
13811 this.startViewMode = this.viewMode;
13814 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
13815 if(!this.calendarWeeks){
13820 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
13821 v.attr('colspan', function(i, val){
13822 return parseInt(val) + 1;
13827 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
13829 this.setStartDate(this.startDate);
13830 this.setEndDate(this.endDate);
13832 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
13839 if(this.isInline) {
13844 picker : function()
13846 return this.el.select('.datepicker', true).first();
13849 fillDow: function()
13851 var dowCnt = this.weekStart;
13860 if(this.calendarWeeks){
13868 while (dowCnt < this.weekStart + 7) {
13872 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
13876 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
13879 fillMonths: function()
13882 var months = this.picker().select('>.datepicker-months td', true).first();
13884 months.dom.innerHTML = '';
13890 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
13893 months.createChild(month);
13901 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
13903 if (this.date < this.startDate) {
13904 this.viewDate = new Date(this.startDate);
13905 } else if (this.date > this.endDate) {
13906 this.viewDate = new Date(this.endDate);
13908 this.viewDate = new Date(this.date);
13916 var d = new Date(this.viewDate),
13917 year = d.getUTCFullYear(),
13918 month = d.getUTCMonth(),
13919 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
13920 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
13921 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
13922 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
13923 currentDate = this.date && this.date.valueOf(),
13924 today = this.UTCToday();
13926 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
13928 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
13930 // this.picker.select('>tfoot th.today').
13931 // .text(dates[this.language].today)
13932 // .toggle(this.todayBtn !== false);
13934 this.updateNavArrows();
13937 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
13939 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
13941 prevMonth.setUTCDate(day);
13943 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
13945 var nextMonth = new Date(prevMonth);
13947 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
13949 nextMonth = nextMonth.valueOf();
13951 var fillMonths = false;
13953 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
13955 while(prevMonth.valueOf() < nextMonth) {
13958 if (prevMonth.getUTCDay() === this.weekStart) {
13960 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
13968 if(this.calendarWeeks){
13969 // ISO 8601: First week contains first thursday.
13970 // ISO also states week starts on Monday, but we can be more abstract here.
13972 // Start of current week: based on weekstart/current date
13973 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
13974 // Thursday of this week
13975 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
13976 // First Thursday of year, year from thursday
13977 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
13978 // Calendar week: ms between thursdays, div ms per day, div 7 days
13979 calWeek = (th - yth) / 864e5 / 7 + 1;
13981 fillMonths.cn.push({
13989 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
13991 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
13994 if (this.todayHighlight &&
13995 prevMonth.getUTCFullYear() == today.getFullYear() &&
13996 prevMonth.getUTCMonth() == today.getMonth() &&
13997 prevMonth.getUTCDate() == today.getDate()) {
13998 clsName += ' today';
14001 if (currentDate && prevMonth.valueOf() === currentDate) {
14002 clsName += ' active';
14005 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14006 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14007 clsName += ' disabled';
14010 fillMonths.cn.push({
14012 cls: 'day ' + clsName,
14013 html: prevMonth.getDate()
14016 prevMonth.setDate(prevMonth.getDate()+1);
14019 var currentYear = this.date && this.date.getUTCFullYear();
14020 var currentMonth = this.date && this.date.getUTCMonth();
14022 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14024 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14025 v.removeClass('active');
14027 if(currentYear === year && k === currentMonth){
14028 v.addClass('active');
14031 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14032 v.addClass('disabled');
14038 year = parseInt(year/10, 10) * 10;
14040 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14042 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14045 for (var i = -1; i < 11; i++) {
14046 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14048 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14056 showMode: function(dir)
14059 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14061 Roo.each(this.picker().select('>div',true).elements, function(v){
14062 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14065 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14070 if(this.isInline) return;
14072 this.picker().removeClass(['bottom', 'top']);
14074 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14076 * place to the top of element!
14080 this.picker().addClass('top');
14081 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14086 this.picker().addClass('bottom');
14088 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14091 parseDate : function(value)
14093 if(!value || value instanceof Date){
14096 var v = Date.parseDate(value, this.format);
14097 if (!v && this.useIso) {
14098 v = Date.parseDate(value, 'Y-m-d');
14100 if(!v && this.altFormats){
14101 if(!this.altFormatsArray){
14102 this.altFormatsArray = this.altFormats.split("|");
14104 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14105 v = Date.parseDate(value, this.altFormatsArray[i]);
14111 formatDate : function(date, fmt)
14113 return (!date || !(date instanceof Date)) ?
14114 date : date.dateFormat(fmt || this.format);
14117 onFocus : function()
14119 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14123 onBlur : function()
14125 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14127 var d = this.inputEl().getValue();
14138 this.picker().show();
14142 this.fireEvent('show', this, this.date);
14147 if(this.isInline) return;
14148 this.picker().hide();
14149 this.viewMode = this.startViewMode;
14152 this.fireEvent('hide', this, this.date);
14156 onMousedown: function(e)
14158 e.stopPropagation();
14159 e.preventDefault();
14164 Roo.bootstrap.DateField.superclass.keyup.call(this);
14168 setValue: function(v)
14170 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14172 var d = new Date(v);
14174 if(isNaN(d.getTime())){
14178 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14182 this.fireEvent('select', this, this.date);
14186 getValue: function()
14188 return this.formatDate(this.date);
14191 fireKey: function(e)
14193 if (!this.picker().isVisible()){
14194 if (e.keyCode == 27) // allow escape to hide and re-show picker
14198 var dateChanged = false,
14200 newDate, newViewDate;
14205 e.preventDefault();
14209 if (!this.keyboardNavigation) break;
14210 dir = e.keyCode == 37 ? -1 : 1;
14213 newDate = this.moveYear(this.date, dir);
14214 newViewDate = this.moveYear(this.viewDate, dir);
14215 } else if (e.shiftKey){
14216 newDate = this.moveMonth(this.date, dir);
14217 newViewDate = this.moveMonth(this.viewDate, dir);
14219 newDate = new Date(this.date);
14220 newDate.setUTCDate(this.date.getUTCDate() + dir);
14221 newViewDate = new Date(this.viewDate);
14222 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14224 if (this.dateWithinRange(newDate)){
14225 this.date = newDate;
14226 this.viewDate = newViewDate;
14227 this.setValue(this.formatDate(this.date));
14229 e.preventDefault();
14230 dateChanged = true;
14235 if (!this.keyboardNavigation) break;
14236 dir = e.keyCode == 38 ? -1 : 1;
14238 newDate = this.moveYear(this.date, dir);
14239 newViewDate = this.moveYear(this.viewDate, dir);
14240 } else if (e.shiftKey){
14241 newDate = this.moveMonth(this.date, dir);
14242 newViewDate = this.moveMonth(this.viewDate, dir);
14244 newDate = new Date(this.date);
14245 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14246 newViewDate = new Date(this.viewDate);
14247 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14249 if (this.dateWithinRange(newDate)){
14250 this.date = newDate;
14251 this.viewDate = newViewDate;
14252 this.setValue(this.formatDate(this.date));
14254 e.preventDefault();
14255 dateChanged = true;
14259 this.setValue(this.formatDate(this.date));
14261 e.preventDefault();
14264 this.setValue(this.formatDate(this.date));
14272 onClick: function(e)
14274 e.stopPropagation();
14275 e.preventDefault();
14277 var target = e.getTarget();
14279 if(target.nodeName.toLowerCase() === 'i'){
14280 target = Roo.get(target).dom.parentNode;
14283 var nodeName = target.nodeName;
14284 var className = target.className;
14285 var html = target.innerHTML;
14287 switch(nodeName.toLowerCase()) {
14289 switch(className) {
14295 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14296 switch(this.viewMode){
14298 this.viewDate = this.moveMonth(this.viewDate, dir);
14302 this.viewDate = this.moveYear(this.viewDate, dir);
14308 var date = new Date();
14309 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14311 this.setValue(this.formatDate(this.date));
14318 if (className.indexOf('disabled') === -1) {
14319 this.viewDate.setUTCDate(1);
14320 if (className.indexOf('month') !== -1) {
14321 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14323 var year = parseInt(html, 10) || 0;
14324 this.viewDate.setUTCFullYear(year);
14333 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
14334 var day = parseInt(html, 10) || 1;
14335 var year = this.viewDate.getUTCFullYear(),
14336 month = this.viewDate.getUTCMonth();
14338 if (className.indexOf('old') !== -1) {
14345 } else if (className.indexOf('new') !== -1) {
14353 this.date = this.UTCDate(year, month, day,0,0,0,0);
14354 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
14356 this.setValue(this.formatDate(this.date));
14363 setStartDate: function(startDate)
14365 this.startDate = startDate || -Infinity;
14366 if (this.startDate !== -Infinity) {
14367 this.startDate = this.parseDate(this.startDate);
14370 this.updateNavArrows();
14373 setEndDate: function(endDate)
14375 this.endDate = endDate || Infinity;
14376 if (this.endDate !== Infinity) {
14377 this.endDate = this.parseDate(this.endDate);
14380 this.updateNavArrows();
14383 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
14385 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
14386 if (typeof(this.daysOfWeekDisabled) !== 'object') {
14387 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
14389 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
14390 return parseInt(d, 10);
14393 this.updateNavArrows();
14396 updateNavArrows: function()
14398 var d = new Date(this.viewDate),
14399 year = d.getUTCFullYear(),
14400 month = d.getUTCMonth();
14402 Roo.each(this.picker().select('.prev', true).elements, function(v){
14404 switch (this.viewMode) {
14407 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
14413 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
14420 Roo.each(this.picker().select('.next', true).elements, function(v){
14422 switch (this.viewMode) {
14425 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
14431 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
14439 moveMonth: function(date, dir)
14441 if (!dir) return date;
14442 var new_date = new Date(date.valueOf()),
14443 day = new_date.getUTCDate(),
14444 month = new_date.getUTCMonth(),
14445 mag = Math.abs(dir),
14447 dir = dir > 0 ? 1 : -1;
14450 // If going back one month, make sure month is not current month
14451 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
14453 return new_date.getUTCMonth() == month;
14455 // If going forward one month, make sure month is as expected
14456 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
14458 return new_date.getUTCMonth() != new_month;
14460 new_month = month + dir;
14461 new_date.setUTCMonth(new_month);
14462 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
14463 if (new_month < 0 || new_month > 11)
14464 new_month = (new_month + 12) % 12;
14466 // For magnitudes >1, move one month at a time...
14467 for (var i=0; i<mag; i++)
14468 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
14469 new_date = this.moveMonth(new_date, dir);
14470 // ...then reset the day, keeping it in the new month
14471 new_month = new_date.getUTCMonth();
14472 new_date.setUTCDate(day);
14474 return new_month != new_date.getUTCMonth();
14477 // Common date-resetting loop -- if date is beyond end of month, make it
14480 new_date.setUTCDate(--day);
14481 new_date.setUTCMonth(new_month);
14486 moveYear: function(date, dir)
14488 return this.moveMonth(date, dir*12);
14491 dateWithinRange: function(date)
14493 return date >= this.startDate && date <= this.endDate;
14499 this.picker().remove();
14504 Roo.apply(Roo.bootstrap.DateField, {
14515 html: '<i class="fa fa-arrow-left"/>'
14525 html: '<i class="fa fa-arrow-right"/>'
14567 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
14568 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
14569 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
14570 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
14571 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
14584 navFnc: 'FullYear',
14589 navFnc: 'FullYear',
14594 Roo.apply(Roo.bootstrap.DateField, {
14598 cls: 'datepicker dropdown-menu',
14602 cls: 'datepicker-days',
14606 cls: 'table-condensed',
14608 Roo.bootstrap.DateField.head,
14612 Roo.bootstrap.DateField.footer
14619 cls: 'datepicker-months',
14623 cls: 'table-condensed',
14625 Roo.bootstrap.DateField.head,
14626 Roo.bootstrap.DateField.content,
14627 Roo.bootstrap.DateField.footer
14634 cls: 'datepicker-years',
14638 cls: 'table-condensed',
14640 Roo.bootstrap.DateField.head,
14641 Roo.bootstrap.DateField.content,
14642 Roo.bootstrap.DateField.footer
14661 * @class Roo.bootstrap.TimeField
14662 * @extends Roo.bootstrap.Input
14663 * Bootstrap DateField class
14667 * Create a new TimeField
14668 * @param {Object} config The config object
14671 Roo.bootstrap.TimeField = function(config){
14672 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
14676 * Fires when this field show.
14677 * @param {Roo.bootstrap.DateField} this
14678 * @param {Mixed} date The date value
14683 * Fires when this field hide.
14684 * @param {Roo.bootstrap.DateField} this
14685 * @param {Mixed} date The date value
14690 * Fires when select a date.
14691 * @param {Roo.bootstrap.DateField} this
14692 * @param {Mixed} date The date value
14698 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
14701 * @cfg {String} format
14702 * The default time format string which can be overriden for localization support. The format must be
14703 * valid according to {@link Date#parseDate} (defaults to 'H:i').
14707 onRender: function(ct, position)
14710 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
14712 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
14714 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14716 this.pop = this.picker().select('>.datepicker-time',true).first();
14717 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
14719 this.picker().on('mousedown', this.onMousedown, this);
14720 this.picker().on('click', this.onClick, this);
14722 this.picker().addClass('datepicker-dropdown');
14727 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
14728 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
14729 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
14730 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
14731 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
14732 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
14736 fireKey: function(e){
14737 if (!this.picker().isVisible()){
14738 if (e.keyCode == 27) // allow escape to hide and re-show picker
14743 e.preventDefault();
14751 this.onTogglePeriod();
14754 this.onIncrementMinutes();
14757 this.onDecrementMinutes();
14766 onClick: function(e) {
14767 e.stopPropagation();
14768 e.preventDefault();
14771 picker : function()
14773 return this.el.select('.datepicker', true).first();
14776 fillTime: function()
14778 var time = this.pop.select('tbody', true).first();
14780 time.dom.innerHTML = '';
14795 cls: 'hours-up glyphicon glyphicon-chevron-up'
14815 cls: 'minutes-up glyphicon glyphicon-chevron-up'
14836 cls: 'timepicker-hour',
14851 cls: 'timepicker-minute',
14866 cls: 'btn btn-primary period',
14888 cls: 'hours-down glyphicon glyphicon-chevron-down'
14908 cls: 'minutes-down glyphicon glyphicon-chevron-down'
14926 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
14933 var hours = this.time.getHours();
14934 var minutes = this.time.getMinutes();
14947 hours = hours - 12;
14951 hours = '0' + hours;
14955 minutes = '0' + minutes;
14958 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
14959 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
14960 this.pop.select('button', true).first().dom.innerHTML = period;
14966 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
14968 var cls = ['bottom'];
14970 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
14977 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
14982 this.picker().addClass(cls.join('-'));
14986 Roo.each(cls, function(c){
14988 _this.picker().setTop(_this.inputEl().getHeight());
14992 _this.picker().setTop(0 - _this.picker().getHeight());
14997 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15001 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15008 onFocus : function()
15010 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15014 onBlur : function()
15016 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15022 this.picker().show();
15027 this.fireEvent('show', this, this.date);
15032 this.picker().hide();
15035 this.fireEvent('hide', this, this.date);
15038 setTime : function()
15041 this.setValue(this.time.format(this.format));
15043 this.fireEvent('select', this, this.date);
15048 onMousedown: function(e){
15049 e.stopPropagation();
15050 e.preventDefault();
15053 onIncrementHours: function()
15055 Roo.log('onIncrementHours');
15056 this.time = this.time.add(Date.HOUR, 1);
15061 onDecrementHours: function()
15063 Roo.log('onDecrementHours');
15064 this.time = this.time.add(Date.HOUR, -1);
15068 onIncrementMinutes: function()
15070 Roo.log('onIncrementMinutes');
15071 this.time = this.time.add(Date.MINUTE, 1);
15075 onDecrementMinutes: function()
15077 Roo.log('onDecrementMinutes');
15078 this.time = this.time.add(Date.MINUTE, -1);
15082 onTogglePeriod: function()
15084 Roo.log('onTogglePeriod');
15085 this.time = this.time.add(Date.HOUR, 12);
15092 Roo.apply(Roo.bootstrap.TimeField, {
15122 cls: 'btn btn-info ok',
15134 Roo.apply(Roo.bootstrap.TimeField, {
15138 cls: 'datepicker dropdown-menu',
15142 cls: 'datepicker-time',
15146 cls: 'table-condensed',
15148 Roo.bootstrap.TimeField.content,
15149 Roo.bootstrap.TimeField.footer
15168 * @class Roo.bootstrap.CheckBox
15169 * @extends Roo.bootstrap.Input
15170 * Bootstrap CheckBox class
15172 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15173 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15174 * @cfg {String} boxLabel The text that appears beside the checkbox
15175 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15176 * @cfg {Boolean} checked initnal the element
15180 * Create a new CheckBox
15181 * @param {Object} config The config object
15184 Roo.bootstrap.CheckBox = function(config){
15185 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15190 * Fires when the element is checked or unchecked.
15191 * @param {Roo.bootstrap.CheckBox} this This input
15192 * @param {Boolean} checked The new checked value
15198 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15200 inputType: 'checkbox',
15207 getAutoCreate : function()
15209 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15215 cfg.cls = 'form-group checkbox' //input-group
15223 type : this.inputType,
15224 value : (!this.checked) ? this.valueOff : this.inputValue,
15225 cls : 'roo-checkbox', //'form-box',
15226 placeholder : this.placeholder || ''
15230 if (this.weight) { // Validity check?
15231 cfg.cls += " checkbox-" + this.weight;
15234 if (this.disabled) {
15235 input.disabled=true;
15239 input.checked = this.checked;
15243 input.name = this.name;
15247 input.cls += ' input-' + this.size;
15251 ['xs','sm','md','lg'].map(function(size){
15252 if (settings[size]) {
15253 cfg.cls += ' col-' + size + '-' + settings[size];
15259 var inputblock = input;
15264 if (this.before || this.after) {
15267 cls : 'input-group',
15271 inputblock.cn.push({
15273 cls : 'input-group-addon',
15277 inputblock.cn.push(input);
15279 inputblock.cn.push({
15281 cls : 'input-group-addon',
15288 if (align ==='left' && this.fieldLabel.length) {
15289 Roo.log("left and has label");
15295 cls : 'control-label col-md-' + this.labelWidth,
15296 html : this.fieldLabel
15300 cls : "col-md-" + (12 - this.labelWidth),
15307 } else if ( this.fieldLabel.length) {
15312 tag: this.boxLabel ? 'span' : 'label',
15314 cls: 'control-label box-input-label',
15315 //cls : 'input-group-addon',
15316 html : this.fieldLabel
15326 Roo.log(" no label && no align");
15327 cfg.cn = [ inputblock ] ;
15336 html: this.boxLabel
15348 * return the real input element.
15350 inputEl: function ()
15352 return this.el.select('input.roo-checkbox',true).first();
15357 return this.el.select('label.control-label',true).first();
15360 initEvents : function()
15362 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
15364 this.inputEl().on('click', this.onClick, this);
15368 onClick : function()
15370 this.setChecked(!this.checked);
15373 setChecked : function(state,suppressEvent)
15375 this.checked = state;
15377 this.inputEl().dom.checked = state;
15379 if(suppressEvent !== true){
15380 this.fireEvent('check', this, state);
15383 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15387 setValue : function(v,suppressEvent)
15389 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
15403 * @class Roo.bootstrap.Radio
15404 * @extends Roo.bootstrap.CheckBox
15405 * Bootstrap Radio class
15408 * Create a new Radio
15409 * @param {Object} config The config object
15412 Roo.bootstrap.Radio = function(config){
15413 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
15417 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
15419 inputType: 'radio',
15423 getAutoCreate : function()
15425 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15431 cfg.cls = 'form-group radio' //input-group
15436 type : this.inputType,
15437 value : (!this.checked) ? this.valueOff : this.inputValue,
15439 placeholder : this.placeholder || ''
15442 if (this.weight) { // Validity check?
15443 cfg.cls += " radio-" + this.weight;
15445 if (this.disabled) {
15446 input.disabled=true;
15450 input.checked = this.checked;
15454 input.name = this.name;
15458 input.cls += ' input-' + this.size;
15462 ['xs','sm','md','lg'].map(function(size){
15463 if (settings[size]) {
15464 cfg.cls += ' col-' + size + '-' + settings[size];
15468 var inputblock = input;
15470 if (this.before || this.after) {
15473 cls : 'input-group',
15477 inputblock.cn.push({
15479 cls : 'input-group-addon',
15483 inputblock.cn.push(input);
15485 inputblock.cn.push({
15487 cls : 'input-group-addon',
15494 if (align ==='left' && this.fieldLabel.length) {
15495 Roo.log("left and has label");
15501 cls : 'control-label col-md-' + this.labelWidth,
15502 html : this.fieldLabel
15506 cls : "col-md-" + (12 - this.labelWidth),
15513 } else if ( this.fieldLabel.length) {
15520 cls: 'control-label box-input-label',
15521 //cls : 'input-group-addon',
15522 html : this.fieldLabel
15532 Roo.log(" no label && no align");
15547 html: this.boxLabel
15554 inputEl: function ()
15556 return this.el.select('input.roo-radio',true).first();
15558 onClick : function()
15560 this.setChecked(true);
15563 setChecked : function(state,suppressEvent)
15566 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
15567 v.dom.checked = false;
15571 this.checked = state;
15572 this.inputEl().dom.checked = state;
15574 if(suppressEvent !== true){
15575 this.fireEvent('check', this, state);
15578 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15582 getGroupValue : function()
15585 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
15586 if(v.dom.checked == true){
15587 value = v.dom.value;
15595 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
15596 * @return {Mixed} value The field value
15598 getValue : function(){
15599 return this.getGroupValue();
15605 //<script type="text/javascript">
15608 * Based Ext JS Library 1.1.1
15609 * Copyright(c) 2006-2007, Ext JS, LLC.
15615 * @class Roo.HtmlEditorCore
15616 * @extends Roo.Component
15617 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
15619 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
15622 Roo.HtmlEditorCore = function(config){
15625 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
15628 * @event initialize
15629 * Fires when the editor is fully initialized (including the iframe)
15630 * @param {Roo.HtmlEditorCore} this
15635 * Fires when the editor is first receives the focus. Any insertion must wait
15636 * until after this event.
15637 * @param {Roo.HtmlEditorCore} this
15641 * @event beforesync
15642 * Fires before the textarea is updated with content from the editor iframe. Return false
15643 * to cancel the sync.
15644 * @param {Roo.HtmlEditorCore} this
15645 * @param {String} html
15649 * @event beforepush
15650 * Fires before the iframe editor is updated with content from the textarea. Return false
15651 * to cancel the push.
15652 * @param {Roo.HtmlEditorCore} this
15653 * @param {String} html
15658 * Fires when the textarea is updated with content from the editor iframe.
15659 * @param {Roo.HtmlEditorCore} this
15660 * @param {String} html
15665 * Fires when the iframe editor is updated with content from the textarea.
15666 * @param {Roo.HtmlEditorCore} this
15667 * @param {String} html
15672 * @event editorevent
15673 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
15674 * @param {Roo.HtmlEditorCore} this
15682 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
15686 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
15692 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
15697 * @cfg {Number} height (in pixels)
15701 * @cfg {Number} width (in pixels)
15706 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
15709 stylesheets: false,
15714 // private properties
15715 validationEvent : false,
15717 initialized : false,
15719 sourceEditMode : false,
15720 onFocus : Roo.emptyFn,
15722 hideMode:'offsets',
15730 * Protected method that will not generally be called directly. It
15731 * is called when the editor initializes the iframe with HTML contents. Override this method if you
15732 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
15734 getDocMarkup : function(){
15737 Roo.log(this.stylesheets);
15739 // inherit styels from page...??
15740 if (this.stylesheets === false) {
15742 Roo.get(document.head).select('style').each(function(node) {
15743 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
15746 Roo.get(document.head).select('link').each(function(node) {
15747 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
15750 } else if (!this.stylesheets.length) {
15752 st = '<style type="text/css">' +
15753 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
15756 Roo.each(this.stylesheets, function(s) {
15757 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
15762 st += '<style type="text/css">' +
15763 'IMG { cursor: pointer } ' +
15767 return '<html><head>' + st +
15768 //<style type="text/css">' +
15769 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
15771 ' </head><body class="roo-htmleditor-body"></body></html>';
15775 onRender : function(ct, position)
15778 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
15779 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
15782 this.el.dom.style.border = '0 none';
15783 this.el.dom.setAttribute('tabIndex', -1);
15784 this.el.addClass('x-hidden hide');
15788 if(Roo.isIE){ // fix IE 1px bogus margin
15789 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
15793 this.frameId = Roo.id();
15797 var iframe = this.owner.wrap.createChild({
15799 cls: 'form-control', // bootstrap..
15801 name: this.frameId,
15802 frameBorder : 'no',
15803 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
15808 this.iframe = iframe.dom;
15810 this.assignDocWin();
15812 this.doc.designMode = 'on';
15815 this.doc.write(this.getDocMarkup());
15819 var task = { // must defer to wait for browser to be ready
15821 //console.log("run task?" + this.doc.readyState);
15822 this.assignDocWin();
15823 if(this.doc.body || this.doc.readyState == 'complete'){
15825 this.doc.designMode="on";
15829 Roo.TaskMgr.stop(task);
15830 this.initEditor.defer(10, this);
15837 Roo.TaskMgr.start(task);
15844 onResize : function(w, h)
15846 Roo.log('resize: ' +w + ',' + h );
15847 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
15851 if(typeof w == 'number'){
15853 this.iframe.style.width = w + 'px';
15855 if(typeof h == 'number'){
15857 this.iframe.style.height = h + 'px';
15859 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
15866 * Toggles the editor between standard and source edit mode.
15867 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
15869 toggleSourceEdit : function(sourceEditMode){
15871 this.sourceEditMode = sourceEditMode === true;
15873 if(this.sourceEditMode){
15875 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
15878 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
15879 //this.iframe.className = '';
15882 //this.setSize(this.owner.wrap.getSize());
15883 //this.fireEvent('editmodechange', this, this.sourceEditMode);
15890 * Protected method that will not generally be called directly. If you need/want
15891 * custom HTML cleanup, this is the method you should override.
15892 * @param {String} html The HTML to be cleaned
15893 * return {String} The cleaned HTML
15895 cleanHtml : function(html){
15896 html = String(html);
15897 if(html.length > 5){
15898 if(Roo.isSafari){ // strip safari nonsense
15899 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
15902 if(html == ' '){
15909 * HTML Editor -> Textarea
15910 * Protected method that will not generally be called directly. Syncs the contents
15911 * of the editor iframe with the textarea.
15913 syncValue : function(){
15914 if(this.initialized){
15915 var bd = (this.doc.body || this.doc.documentElement);
15916 //this.cleanUpPaste(); -- this is done else where and causes havoc..
15917 var html = bd.innerHTML;
15919 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
15920 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
15922 html = '<div style="'+m[0]+'">' + html + '</div>';
15925 html = this.cleanHtml(html);
15926 // fix up the special chars.. normaly like back quotes in word...
15927 // however we do not want to do this with chinese..
15928 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
15929 var cc = b.charCodeAt();
15931 (cc >= 0x4E00 && cc < 0xA000 ) ||
15932 (cc >= 0x3400 && cc < 0x4E00 ) ||
15933 (cc >= 0xf900 && cc < 0xfb00 )
15939 if(this.owner.fireEvent('beforesync', this, html) !== false){
15940 this.el.dom.value = html;
15941 this.owner.fireEvent('sync', this, html);
15947 * Protected method that will not generally be called directly. Pushes the value of the textarea
15948 * into the iframe editor.
15950 pushValue : function(){
15951 if(this.initialized){
15952 var v = this.el.dom.value.trim();
15954 // if(v.length < 1){
15958 if(this.owner.fireEvent('beforepush', this, v) !== false){
15959 var d = (this.doc.body || this.doc.documentElement);
15961 this.cleanUpPaste();
15962 this.el.dom.value = d.innerHTML;
15963 this.owner.fireEvent('push', this, v);
15969 deferFocus : function(){
15970 this.focus.defer(10, this);
15974 focus : function(){
15975 if(this.win && !this.sourceEditMode){
15982 assignDocWin: function()
15984 var iframe = this.iframe;
15987 this.doc = iframe.contentWindow.document;
15988 this.win = iframe.contentWindow;
15990 if (!Roo.get(this.frameId)) {
15993 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
15994 this.win = Roo.get(this.frameId).dom.contentWindow;
15999 initEditor : function(){
16000 //console.log("INIT EDITOR");
16001 this.assignDocWin();
16005 this.doc.designMode="on";
16007 this.doc.write(this.getDocMarkup());
16010 var dbody = (this.doc.body || this.doc.documentElement);
16011 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16012 // this copies styles from the containing element into thsi one..
16013 // not sure why we need all of this..
16014 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16016 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16017 //ss['background-attachment'] = 'fixed'; // w3c
16018 dbody.bgProperties = 'fixed'; // ie
16019 //Roo.DomHelper.applyStyles(dbody, ss);
16020 Roo.EventManager.on(this.doc, {
16021 //'mousedown': this.onEditorEvent,
16022 'mouseup': this.onEditorEvent,
16023 'dblclick': this.onEditorEvent,
16024 'click': this.onEditorEvent,
16025 'keyup': this.onEditorEvent,
16030 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16032 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16033 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16035 this.initialized = true;
16037 this.owner.fireEvent('initialize', this);
16042 onDestroy : function(){
16048 //for (var i =0; i < this.toolbars.length;i++) {
16049 // // fixme - ask toolbars for heights?
16050 // this.toolbars[i].onDestroy();
16053 //this.wrap.dom.innerHTML = '';
16054 //this.wrap.remove();
16059 onFirstFocus : function(){
16061 this.assignDocWin();
16064 this.activated = true;
16067 if(Roo.isGecko){ // prevent silly gecko errors
16069 var s = this.win.getSelection();
16070 if(!s.focusNode || s.focusNode.nodeType != 3){
16071 var r = s.getRangeAt(0);
16072 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16077 this.execCmd('useCSS', true);
16078 this.execCmd('styleWithCSS', false);
16081 this.owner.fireEvent('activate', this);
16085 adjustFont: function(btn){
16086 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16087 //if(Roo.isSafari){ // safari
16090 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16091 if(Roo.isSafari){ // safari
16092 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16093 v = (v < 10) ? 10 : v;
16094 v = (v > 48) ? 48 : v;
16095 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16100 v = Math.max(1, v+adjust);
16102 this.execCmd('FontSize', v );
16105 onEditorEvent : function(e){
16106 this.owner.fireEvent('editorevent', this, e);
16107 // this.updateToolbar();
16108 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16111 insertTag : function(tg)
16113 // could be a bit smarter... -> wrap the current selected tRoo..
16114 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16116 range = this.createRange(this.getSelection());
16117 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16118 wrappingNode.appendChild(range.extractContents());
16119 range.insertNode(wrappingNode);
16126 this.execCmd("formatblock", tg);
16130 insertText : function(txt)
16134 var range = this.createRange();
16135 range.deleteContents();
16136 //alert(Sender.getAttribute('label'));
16138 range.insertNode(this.doc.createTextNode(txt));
16144 * Executes a Midas editor command on the editor document and performs necessary focus and
16145 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16146 * @param {String} cmd The Midas command
16147 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16149 relayCmd : function(cmd, value){
16151 this.execCmd(cmd, value);
16152 this.owner.fireEvent('editorevent', this);
16153 //this.updateToolbar();
16154 this.owner.deferFocus();
16158 * Executes a Midas editor command directly on the editor document.
16159 * For visual commands, you should use {@link #relayCmd} instead.
16160 * <b>This should only be called after the editor is initialized.</b>
16161 * @param {String} cmd The Midas command
16162 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16164 execCmd : function(cmd, value){
16165 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16172 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16174 * @param {String} text | dom node..
16176 insertAtCursor : function(text)
16181 if(!this.activated){
16187 var r = this.doc.selection.createRange();
16198 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16202 // from jquery ui (MIT licenced)
16204 var win = this.win;
16206 if (win.getSelection && win.getSelection().getRangeAt) {
16207 range = win.getSelection().getRangeAt(0);
16208 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16209 range.insertNode(node);
16210 } else if (win.document.selection && win.document.selection.createRange) {
16211 // no firefox support
16212 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16213 win.document.selection.createRange().pasteHTML(txt);
16215 // no firefox support
16216 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16217 this.execCmd('InsertHTML', txt);
16226 mozKeyPress : function(e){
16228 var c = e.getCharCode(), cmd;
16231 c = String.fromCharCode(c).toLowerCase();
16245 this.cleanUpPaste.defer(100, this);
16253 e.preventDefault();
16261 fixKeys : function(){ // load time branching for fastest keydown performance
16263 return function(e){
16264 var k = e.getKey(), r;
16267 r = this.doc.selection.createRange();
16270 r.pasteHTML('    ');
16277 r = this.doc.selection.createRange();
16279 var target = r.parentElement();
16280 if(!target || target.tagName.toLowerCase() != 'li'){
16282 r.pasteHTML('<br />');
16288 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16289 this.cleanUpPaste.defer(100, this);
16295 }else if(Roo.isOpera){
16296 return function(e){
16297 var k = e.getKey();
16301 this.execCmd('InsertHTML','    ');
16304 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16305 this.cleanUpPaste.defer(100, this);
16310 }else if(Roo.isSafari){
16311 return function(e){
16312 var k = e.getKey();
16316 this.execCmd('InsertText','\t');
16320 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16321 this.cleanUpPaste.defer(100, this);
16329 getAllAncestors: function()
16331 var p = this.getSelectedNode();
16334 a.push(p); // push blank onto stack..
16335 p = this.getParentElement();
16339 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
16343 a.push(this.doc.body);
16347 lastSelNode : false,
16350 getSelection : function()
16352 this.assignDocWin();
16353 return Roo.isIE ? this.doc.selection : this.win.getSelection();
16356 getSelectedNode: function()
16358 // this may only work on Gecko!!!
16360 // should we cache this!!!!
16365 var range = this.createRange(this.getSelection()).cloneRange();
16368 var parent = range.parentElement();
16370 var testRange = range.duplicate();
16371 testRange.moveToElementText(parent);
16372 if (testRange.inRange(range)) {
16375 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
16378 parent = parent.parentElement;
16383 // is ancestor a text element.
16384 var ac = range.commonAncestorContainer;
16385 if (ac.nodeType == 3) {
16386 ac = ac.parentNode;
16389 var ar = ac.childNodes;
16392 var other_nodes = [];
16393 var has_other_nodes = false;
16394 for (var i=0;i<ar.length;i++) {
16395 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
16398 // fullly contained node.
16400 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
16405 // probably selected..
16406 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
16407 other_nodes.push(ar[i]);
16411 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
16416 has_other_nodes = true;
16418 if (!nodes.length && other_nodes.length) {
16419 nodes= other_nodes;
16421 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
16427 createRange: function(sel)
16429 // this has strange effects when using with
16430 // top toolbar - not sure if it's a great idea.
16431 //this.editor.contentWindow.focus();
16432 if (typeof sel != "undefined") {
16434 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
16436 return this.doc.createRange();
16439 return this.doc.createRange();
16442 getParentElement: function()
16445 this.assignDocWin();
16446 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
16448 var range = this.createRange(sel);
16451 var p = range.commonAncestorContainer;
16452 while (p.nodeType == 3) { // text node
16463 * Range intersection.. the hard stuff...
16467 * [ -- selected range --- ]
16471 * if end is before start or hits it. fail.
16472 * if start is after end or hits it fail.
16474 * if either hits (but other is outside. - then it's not
16480 // @see http://www.thismuchiknow.co.uk/?p=64.
16481 rangeIntersectsNode : function(range, node)
16483 var nodeRange = node.ownerDocument.createRange();
16485 nodeRange.selectNode(node);
16487 nodeRange.selectNodeContents(node);
16490 var rangeStartRange = range.cloneRange();
16491 rangeStartRange.collapse(true);
16493 var rangeEndRange = range.cloneRange();
16494 rangeEndRange.collapse(false);
16496 var nodeStartRange = nodeRange.cloneRange();
16497 nodeStartRange.collapse(true);
16499 var nodeEndRange = nodeRange.cloneRange();
16500 nodeEndRange.collapse(false);
16502 return rangeStartRange.compareBoundaryPoints(
16503 Range.START_TO_START, nodeEndRange) == -1 &&
16504 rangeEndRange.compareBoundaryPoints(
16505 Range.START_TO_START, nodeStartRange) == 1;
16509 rangeCompareNode : function(range, node)
16511 var nodeRange = node.ownerDocument.createRange();
16513 nodeRange.selectNode(node);
16515 nodeRange.selectNodeContents(node);
16519 range.collapse(true);
16521 nodeRange.collapse(true);
16523 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
16524 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
16526 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
16528 var nodeIsBefore = ss == 1;
16529 var nodeIsAfter = ee == -1;
16531 if (nodeIsBefore && nodeIsAfter)
16533 if (!nodeIsBefore && nodeIsAfter)
16534 return 1; //right trailed.
16536 if (nodeIsBefore && !nodeIsAfter)
16537 return 2; // left trailed.
16542 // private? - in a new class?
16543 cleanUpPaste : function()
16545 // cleans up the whole document..
16546 Roo.log('cleanuppaste');
16548 this.cleanUpChildren(this.doc.body);
16549 var clean = this.cleanWordChars(this.doc.body.innerHTML);
16550 if (clean != this.doc.body.innerHTML) {
16551 this.doc.body.innerHTML = clean;
16556 cleanWordChars : function(input) {// change the chars to hex code
16557 var he = Roo.HtmlEditorCore;
16559 var output = input;
16560 Roo.each(he.swapCodes, function(sw) {
16561 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
16563 output = output.replace(swapper, sw[1]);
16570 cleanUpChildren : function (n)
16572 if (!n.childNodes.length) {
16575 for (var i = n.childNodes.length-1; i > -1 ; i--) {
16576 this.cleanUpChild(n.childNodes[i]);
16583 cleanUpChild : function (node)
16586 //console.log(node);
16587 if (node.nodeName == "#text") {
16588 // clean up silly Windows -- stuff?
16591 if (node.nodeName == "#comment") {
16592 node.parentNode.removeChild(node);
16593 // clean up silly Windows -- stuff?
16597 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
16599 node.parentNode.removeChild(node);
16604 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
16606 // remove <a name=....> as rendering on yahoo mailer is borked with this.
16607 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
16609 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
16610 // remove_keep_children = true;
16613 if (remove_keep_children) {
16614 this.cleanUpChildren(node);
16615 // inserts everything just before this node...
16616 while (node.childNodes.length) {
16617 var cn = node.childNodes[0];
16618 node.removeChild(cn);
16619 node.parentNode.insertBefore(cn, node);
16621 node.parentNode.removeChild(node);
16625 if (!node.attributes || !node.attributes.length) {
16626 this.cleanUpChildren(node);
16630 function cleanAttr(n,v)
16633 if (v.match(/^\./) || v.match(/^\//)) {
16636 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
16639 if (v.match(/^#/)) {
16642 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
16643 node.removeAttribute(n);
16647 function cleanStyle(n,v)
16649 if (v.match(/expression/)) { //XSS?? should we even bother..
16650 node.removeAttribute(n);
16653 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
16654 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
16657 var parts = v.split(/;/);
16660 Roo.each(parts, function(p) {
16661 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
16665 var l = p.split(':').shift().replace(/\s+/g,'');
16666 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
16668 if ( cblack.indexOf(l) > -1) {
16669 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
16670 //node.removeAttribute(n);
16674 // only allow 'c whitelisted system attributes'
16675 if ( cwhite.length && cwhite.indexOf(l) < 0) {
16676 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
16677 //node.removeAttribute(n);
16687 if (clean.length) {
16688 node.setAttribute(n, clean.join(';'));
16690 node.removeAttribute(n);
16696 for (var i = node.attributes.length-1; i > -1 ; i--) {
16697 var a = node.attributes[i];
16700 if (a.name.toLowerCase().substr(0,2)=='on') {
16701 node.removeAttribute(a.name);
16704 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
16705 node.removeAttribute(a.name);
16708 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
16709 cleanAttr(a.name,a.value); // fixme..
16712 if (a.name == 'style') {
16713 cleanStyle(a.name,a.value);
16716 /// clean up MS crap..
16717 // tecnically this should be a list of valid class'es..
16720 if (a.name == 'class') {
16721 if (a.value.match(/^Mso/)) {
16722 node.className = '';
16725 if (a.value.match(/body/)) {
16726 node.className = '';
16737 this.cleanUpChildren(node);
16742 * Clean up MS wordisms...
16744 cleanWord : function(node)
16747 var cleanWordChildren = function()
16749 if (!node.childNodes.length) {
16752 for (var i = node.childNodes.length-1; i > -1 ; i--) {
16753 _t.cleanWord(node.childNodes[i]);
16759 this.cleanWord(this.doc.body);
16762 if (node.nodeName == "#text") {
16763 // clean up silly Windows -- stuff?
16766 if (node.nodeName == "#comment") {
16767 node.parentNode.removeChild(node);
16768 // clean up silly Windows -- stuff?
16772 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
16773 node.parentNode.removeChild(node);
16777 // remove - but keep children..
16778 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
16779 while (node.childNodes.length) {
16780 var cn = node.childNodes[0];
16781 node.removeChild(cn);
16782 node.parentNode.insertBefore(cn, node);
16784 node.parentNode.removeChild(node);
16785 cleanWordChildren();
16789 if (node.className.length) {
16791 var cn = node.className.split(/\W+/);
16793 Roo.each(cn, function(cls) {
16794 if (cls.match(/Mso[a-zA-Z]+/)) {
16799 node.className = cna.length ? cna.join(' ') : '';
16801 node.removeAttribute("class");
16805 if (node.hasAttribute("lang")) {
16806 node.removeAttribute("lang");
16809 if (node.hasAttribute("style")) {
16811 var styles = node.getAttribute("style").split(";");
16813 Roo.each(styles, function(s) {
16814 if (!s.match(/:/)) {
16817 var kv = s.split(":");
16818 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
16821 // what ever is left... we allow.
16824 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
16825 if (!nstyle.length) {
16826 node.removeAttribute('style');
16830 cleanWordChildren();
16834 domToHTML : function(currentElement, depth, nopadtext) {
16836 depth = depth || 0;
16837 nopadtext = nopadtext || false;
16839 if (!currentElement) {
16840 return this.domToHTML(this.doc.body);
16843 //Roo.log(currentElement);
16845 var allText = false;
16846 var nodeName = currentElement.nodeName;
16847 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
16849 if (nodeName == '#text') {
16850 return currentElement.nodeValue;
16855 if (nodeName != 'BODY') {
16858 // Prints the node tagName, such as <A>, <IMG>, etc
16861 for(i = 0; i < currentElement.attributes.length;i++) {
16863 var aname = currentElement.attributes.item(i).name;
16864 if (!currentElement.attributes.item(i).value.length) {
16867 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
16870 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
16879 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
16882 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
16887 // Traverse the tree
16889 var currentElementChild = currentElement.childNodes.item(i);
16890 var allText = true;
16891 var innerHTML = '';
16893 while (currentElementChild) {
16894 // Formatting code (indent the tree so it looks nice on the screen)
16895 var nopad = nopadtext;
16896 if (lastnode == 'SPAN') {
16900 if (currentElementChild.nodeName == '#text') {
16901 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
16902 if (!nopad && toadd.length > 80) {
16903 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
16905 innerHTML += toadd;
16908 currentElementChild = currentElement.childNodes.item(i);
16914 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
16916 // Recursively traverse the tree structure of the child node
16917 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
16918 lastnode = currentElementChild.nodeName;
16920 currentElementChild=currentElement.childNodes.item(i);
16926 // The remaining code is mostly for formatting the tree
16927 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
16932 ret+= "</"+tagName+">";
16938 // hide stuff that is not compatible
16952 * @event specialkey
16956 * @cfg {String} fieldClass @hide
16959 * @cfg {String} focusClass @hide
16962 * @cfg {String} autoCreate @hide
16965 * @cfg {String} inputType @hide
16968 * @cfg {String} invalidClass @hide
16971 * @cfg {String} invalidText @hide
16974 * @cfg {String} msgFx @hide
16977 * @cfg {String} validateOnBlur @hide
16981 Roo.HtmlEditorCore.white = [
16982 'area', 'br', 'img', 'input', 'hr', 'wbr',
16984 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
16985 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
16986 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
16987 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
16988 'table', 'ul', 'xmp',
16990 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
16993 'dir', 'menu', 'ol', 'ul', 'dl',
16999 Roo.HtmlEditorCore.black = [
17000 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17002 'base', 'basefont', 'bgsound', 'blink', 'body',
17003 'frame', 'frameset', 'head', 'html', 'ilayer',
17004 'iframe', 'layer', 'link', 'meta', 'object',
17005 'script', 'style' ,'title', 'xml' // clean later..
17007 Roo.HtmlEditorCore.clean = [
17008 'script', 'style', 'title', 'xml'
17010 Roo.HtmlEditorCore.remove = [
17015 Roo.HtmlEditorCore.ablack = [
17019 Roo.HtmlEditorCore.aclean = [
17020 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17024 Roo.HtmlEditorCore.pwhite= [
17025 'http', 'https', 'mailto'
17028 // white listed style attributes.
17029 Roo.HtmlEditorCore.cwhite= [
17030 // 'text-align', /// default is to allow most things..
17036 // black listed style attributes.
17037 Roo.HtmlEditorCore.cblack= [
17038 // 'font-size' -- this can be set by the project
17042 Roo.HtmlEditorCore.swapCodes =[
17061 * @class Roo.bootstrap.HtmlEditor
17062 * @extends Roo.bootstrap.TextArea
17063 * Bootstrap HtmlEditor class
17066 * Create a new HtmlEditor
17067 * @param {Object} config The config object
17070 Roo.bootstrap.HtmlEditor = function(config){
17071 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17072 if (!this.toolbars) {
17073 this.toolbars = [];
17075 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17078 * @event initialize
17079 * Fires when the editor is fully initialized (including the iframe)
17080 * @param {HtmlEditor} this
17085 * Fires when the editor is first receives the focus. Any insertion must wait
17086 * until after this event.
17087 * @param {HtmlEditor} this
17091 * @event beforesync
17092 * Fires before the textarea is updated with content from the editor iframe. Return false
17093 * to cancel the sync.
17094 * @param {HtmlEditor} this
17095 * @param {String} html
17099 * @event beforepush
17100 * Fires before the iframe editor is updated with content from the textarea. Return false
17101 * to cancel the push.
17102 * @param {HtmlEditor} this
17103 * @param {String} html
17108 * Fires when the textarea is updated with content from the editor iframe.
17109 * @param {HtmlEditor} this
17110 * @param {String} html
17115 * Fires when the iframe editor is updated with content from the textarea.
17116 * @param {HtmlEditor} this
17117 * @param {String} html
17121 * @event editmodechange
17122 * Fires when the editor switches edit modes
17123 * @param {HtmlEditor} this
17124 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17126 editmodechange: true,
17128 * @event editorevent
17129 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17130 * @param {HtmlEditor} this
17134 * @event firstfocus
17135 * Fires when on first focus - needed by toolbars..
17136 * @param {HtmlEditor} this
17141 * Auto save the htmlEditor value as a file into Events
17142 * @param {HtmlEditor} this
17146 * @event savedpreview
17147 * preview the saved version of htmlEditor
17148 * @param {HtmlEditor} this
17155 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17159 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17164 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17169 * @cfg {Number} height (in pixels)
17173 * @cfg {Number} width (in pixels)
17178 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17181 stylesheets: false,
17186 // private properties
17187 validationEvent : false,
17189 initialized : false,
17192 onFocus : Roo.emptyFn,
17194 hideMode:'offsets',
17197 tbContainer : false,
17199 toolbarContainer :function() {
17200 return this.wrap.select('.x-html-editor-tb',true).first();
17204 * Protected method that will not generally be called directly. It
17205 * is called when the editor creates its toolbar. Override this method if you need to
17206 * add custom toolbar buttons.
17207 * @param {HtmlEditor} editor
17209 createToolbar : function(){
17211 Roo.log("create toolbars");
17213 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17214 this.toolbars[0].render(this.toolbarContainer());
17218 // if (!editor.toolbars || !editor.toolbars.length) {
17219 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17222 // for (var i =0 ; i < editor.toolbars.length;i++) {
17223 // editor.toolbars[i] = Roo.factory(
17224 // typeof(editor.toolbars[i]) == 'string' ?
17225 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
17226 // Roo.bootstrap.HtmlEditor);
17227 // editor.toolbars[i].init(editor);
17233 onRender : function(ct, position)
17235 // Roo.log("Call onRender: " + this.xtype);
17237 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17239 this.wrap = this.inputEl().wrap({
17240 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17243 this.editorcore.onRender(ct, position);
17245 if (this.resizable) {
17246 this.resizeEl = new Roo.Resizable(this.wrap, {
17250 minHeight : this.height,
17251 height: this.height,
17252 handles : this.resizable,
17255 resize : function(r, w, h) {
17256 _t.onResize(w,h); // -something
17262 this.createToolbar(this);
17265 if(!this.width && this.resizable){
17266 this.setSize(this.wrap.getSize());
17268 if (this.resizeEl) {
17269 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17270 // should trigger onReize..
17276 onResize : function(w, h)
17278 Roo.log('resize: ' +w + ',' + h );
17279 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17283 if(this.inputEl() ){
17284 if(typeof w == 'number'){
17285 var aw = w - this.wrap.getFrameWidth('lr');
17286 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17289 if(typeof h == 'number'){
17290 var tbh = -11; // fixme it needs to tool bar size!
17291 for (var i =0; i < this.toolbars.length;i++) {
17292 // fixme - ask toolbars for heights?
17293 tbh += this.toolbars[i].el.getHeight();
17294 //if (this.toolbars[i].footer) {
17295 // tbh += this.toolbars[i].footer.el.getHeight();
17303 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17304 ah -= 5; // knock a few pixes off for look..
17305 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17309 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17310 this.editorcore.onResize(ew,eh);
17315 * Toggles the editor between standard and source edit mode.
17316 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17318 toggleSourceEdit : function(sourceEditMode)
17320 this.editorcore.toggleSourceEdit(sourceEditMode);
17322 if(this.editorcore.sourceEditMode){
17323 Roo.log('editor - showing textarea');
17326 // Roo.log(this.syncValue());
17328 this.inputEl().removeClass(['hide', 'x-hidden']);
17329 this.inputEl().dom.removeAttribute('tabIndex');
17330 this.inputEl().focus();
17332 Roo.log('editor - hiding textarea');
17334 // Roo.log(this.pushValue());
17337 this.inputEl().addClass(['hide', 'x-hidden']);
17338 this.inputEl().dom.setAttribute('tabIndex', -1);
17339 //this.deferFocus();
17342 if(this.resizable){
17343 this.setSize(this.wrap.getSize());
17346 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
17349 // private (for BoxComponent)
17350 adjustSize : Roo.BoxComponent.prototype.adjustSize,
17352 // private (for BoxComponent)
17353 getResizeEl : function(){
17357 // private (for BoxComponent)
17358 getPositionEl : function(){
17363 initEvents : function(){
17364 this.originalValue = this.getValue();
17368 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17371 // markInvalid : Roo.emptyFn,
17373 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17376 // clearInvalid : Roo.emptyFn,
17378 setValue : function(v){
17379 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
17380 this.editorcore.pushValue();
17385 deferFocus : function(){
17386 this.focus.defer(10, this);
17390 focus : function(){
17391 this.editorcore.focus();
17397 onDestroy : function(){
17403 for (var i =0; i < this.toolbars.length;i++) {
17404 // fixme - ask toolbars for heights?
17405 this.toolbars[i].onDestroy();
17408 this.wrap.dom.innerHTML = '';
17409 this.wrap.remove();
17414 onFirstFocus : function(){
17415 //Roo.log("onFirstFocus");
17416 this.editorcore.onFirstFocus();
17417 for (var i =0; i < this.toolbars.length;i++) {
17418 this.toolbars[i].onFirstFocus();
17424 syncValue : function()
17426 this.editorcore.syncValue();
17429 pushValue : function()
17431 this.editorcore.pushValue();
17435 // hide stuff that is not compatible
17449 * @event specialkey
17453 * @cfg {String} fieldClass @hide
17456 * @cfg {String} focusClass @hide
17459 * @cfg {String} autoCreate @hide
17462 * @cfg {String} inputType @hide
17465 * @cfg {String} invalidClass @hide
17468 * @cfg {String} invalidText @hide
17471 * @cfg {String} msgFx @hide
17474 * @cfg {String} validateOnBlur @hide
17483 Roo.namespace('Roo.bootstrap.htmleditor');
17485 * @class Roo.bootstrap.HtmlEditorToolbar1
17490 new Roo.bootstrap.HtmlEditor({
17493 new Roo.bootstrap.HtmlEditorToolbar1({
17494 disable : { fonts: 1 , format: 1, ..., ... , ...],
17500 * @cfg {Object} disable List of elements to disable..
17501 * @cfg {Array} btns List of additional buttons.
17505 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
17508 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
17511 Roo.apply(this, config);
17513 // default disabled, based on 'good practice'..
17514 this.disable = this.disable || {};
17515 Roo.applyIf(this.disable, {
17518 specialElements : true
17520 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
17522 this.editor = config.editor;
17523 this.editorcore = config.editor.editorcore;
17525 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
17527 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
17528 // dont call parent... till later.
17530 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
17535 editorcore : false,
17540 "h1","h2","h3","h4","h5","h6",
17542 "abbr", "acronym", "address", "cite", "samp", "var",
17546 onRender : function(ct, position)
17548 // Roo.log("Call onRender: " + this.xtype);
17550 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
17552 this.el.dom.style.marginBottom = '0';
17554 var editorcore = this.editorcore;
17555 var editor= this.editor;
17558 var btn = function(id,cmd , toggle, handler){
17560 var event = toggle ? 'toggle' : 'click';
17565 xns: Roo.bootstrap,
17568 enableToggle:toggle !== false,
17570 pressed : toggle ? false : null,
17573 a.listeners[toggle ? 'toggle' : 'click'] = function() {
17574 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
17583 xns: Roo.bootstrap,
17584 glyphicon : 'font',
17588 xns: Roo.bootstrap,
17592 Roo.each(this.formats, function(f) {
17593 style.menu.items.push({
17595 xns: Roo.bootstrap,
17596 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
17601 editorcore.insertTag(this.tagname);
17608 children.push(style);
17611 btn('bold',false,true);
17612 btn('italic',false,true);
17613 btn('align-left', 'justifyleft',true);
17614 btn('align-center', 'justifycenter',true);
17615 btn('align-right' , 'justifyright',true);
17616 btn('link', false, false, function(btn) {
17617 //Roo.log("create link?");
17618 var url = prompt(this.createLinkText, this.defaultLinkValue);
17619 if(url && url != 'http:/'+'/'){
17620 this.editorcore.relayCmd('createlink', url);
17623 btn('list','insertunorderedlist',true);
17624 btn('pencil', false,true, function(btn){
17627 this.toggleSourceEdit(btn.pressed);
17633 xns: Roo.bootstrap,
17638 xns: Roo.bootstrap,
17643 cog.menu.items.push({
17645 xns: Roo.bootstrap,
17646 html : Clean styles,
17651 editorcore.insertTag(this.tagname);
17660 this.xtype = 'NavSimplebar';
17662 for(var i=0;i< children.length;i++) {
17664 this.buttons.add(this.addxtypeChild(children[i]));
17668 editor.on('editorevent', this.updateToolbar, this);
17670 onBtnClick : function(id)
17672 this.editorcore.relayCmd(id);
17673 this.editorcore.focus();
17677 * Protected method that will not generally be called directly. It triggers
17678 * a toolbar update by reading the markup state of the current selection in the editor.
17680 updateToolbar: function(){
17682 if(!this.editorcore.activated){
17683 this.editor.onFirstFocus(); // is this neeed?
17687 var btns = this.buttons;
17688 var doc = this.editorcore.doc;
17689 btns.get('bold').setActive(doc.queryCommandState('bold'));
17690 btns.get('italic').setActive(doc.queryCommandState('italic'));
17691 //btns.get('underline').setActive(doc.queryCommandState('underline'));
17693 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
17694 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
17695 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
17697 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
17698 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
17701 var ans = this.editorcore.getAllAncestors();
17702 if (this.formatCombo) {
17705 var store = this.formatCombo.store;
17706 this.formatCombo.setValue("");
17707 for (var i =0; i < ans.length;i++) {
17708 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
17710 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
17718 // hides menus... - so this cant be on a menu...
17719 Roo.bootstrap.MenuMgr.hideAll();
17721 Roo.bootstrap.MenuMgr.hideAll();
17722 //this.editorsyncValue();
17724 onFirstFocus: function() {
17725 this.buttons.each(function(item){
17729 toggleSourceEdit : function(sourceEditMode){
17732 if(sourceEditMode){
17733 Roo.log("disabling buttons");
17734 this.buttons.each( function(item){
17735 if(item.cmd != 'pencil'){
17741 Roo.log("enabling buttons");
17742 if(this.editorcore.initialized){
17743 this.buttons.each( function(item){
17749 Roo.log("calling toggole on editor");
17750 // tell the editor that it's been pressed..
17751 this.editor.toggleSourceEdit(sourceEditMode);
17761 * @class Roo.bootstrap.Table.AbstractSelectionModel
17762 * @extends Roo.util.Observable
17763 * Abstract base class for grid SelectionModels. It provides the interface that should be
17764 * implemented by descendant classes. This class should not be directly instantiated.
17767 Roo.bootstrap.Table.AbstractSelectionModel = function(){
17768 this.locked = false;
17769 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
17773 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
17774 /** @ignore Called by the grid automatically. Do not call directly. */
17775 init : function(grid){
17781 * Locks the selections.
17784 this.locked = true;
17788 * Unlocks the selections.
17790 unlock : function(){
17791 this.locked = false;
17795 * Returns true if the selections are locked.
17796 * @return {Boolean}
17798 isLocked : function(){
17799 return this.locked;
17803 * @extends Roo.bootstrap.Table.AbstractSelectionModel
17804 * @class Roo.bootstrap.Table.RowSelectionModel
17805 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
17806 * It supports multiple selections and keyboard selection/navigation.
17808 * @param {Object} config
17811 Roo.bootstrap.Table.RowSelectionModel = function(config){
17812 Roo.apply(this, config);
17813 this.selections = new Roo.util.MixedCollection(false, function(o){
17818 this.lastActive = false;
17822 * @event selectionchange
17823 * Fires when the selection changes
17824 * @param {SelectionModel} this
17826 "selectionchange" : true,
17828 * @event afterselectionchange
17829 * Fires after the selection changes (eg. by key press or clicking)
17830 * @param {SelectionModel} this
17832 "afterselectionchange" : true,
17834 * @event beforerowselect
17835 * Fires when a row is selected being selected, return false to cancel.
17836 * @param {SelectionModel} this
17837 * @param {Number} rowIndex The selected index
17838 * @param {Boolean} keepExisting False if other selections will be cleared
17840 "beforerowselect" : true,
17843 * Fires when a row is selected.
17844 * @param {SelectionModel} this
17845 * @param {Number} rowIndex The selected index
17846 * @param {Roo.data.Record} r The record
17848 "rowselect" : true,
17850 * @event rowdeselect
17851 * Fires when a row is deselected.
17852 * @param {SelectionModel} this
17853 * @param {Number} rowIndex The selected index
17855 "rowdeselect" : true
17857 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
17858 this.locked = false;
17861 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
17863 * @cfg {Boolean} singleSelect
17864 * True to allow selection of only one row at a time (defaults to false)
17866 singleSelect : false,
17869 initEvents : function(){
17871 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
17872 this.grid.on("mousedown", this.handleMouseDown, this);
17873 }else{ // allow click to work like normal
17874 this.grid.on("rowclick", this.handleDragableRowClick, this);
17877 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
17878 "up" : function(e){
17880 this.selectPrevious(e.shiftKey);
17881 }else if(this.last !== false && this.lastActive !== false){
17882 var last = this.last;
17883 this.selectRange(this.last, this.lastActive-1);
17884 this.grid.getView().focusRow(this.lastActive);
17885 if(last !== false){
17889 this.selectFirstRow();
17891 this.fireEvent("afterselectionchange", this);
17893 "down" : function(e){
17895 this.selectNext(e.shiftKey);
17896 }else if(this.last !== false && this.lastActive !== false){
17897 var last = this.last;
17898 this.selectRange(this.last, this.lastActive+1);
17899 this.grid.getView().focusRow(this.lastActive);
17900 if(last !== false){
17904 this.selectFirstRow();
17906 this.fireEvent("afterselectionchange", this);
17911 var view = this.grid.view;
17912 view.on("refresh", this.onRefresh, this);
17913 view.on("rowupdated", this.onRowUpdated, this);
17914 view.on("rowremoved", this.onRemove, this);
17918 onRefresh : function(){
17919 var ds = this.grid.dataSource, i, v = this.grid.view;
17920 var s = this.selections;
17921 s.each(function(r){
17922 if((i = ds.indexOfId(r.id)) != -1){
17931 onRemove : function(v, index, r){
17932 this.selections.remove(r);
17936 onRowUpdated : function(v, index, r){
17937 if(this.isSelected(r)){
17938 v.onRowSelect(index);
17944 * @param {Array} records The records to select
17945 * @param {Boolean} keepExisting (optional) True to keep existing selections
17947 selectRecords : function(records, keepExisting){
17949 this.clearSelections();
17951 var ds = this.grid.dataSource;
17952 for(var i = 0, len = records.length; i < len; i++){
17953 this.selectRow(ds.indexOf(records[i]), true);
17958 * Gets the number of selected rows.
17961 getCount : function(){
17962 return this.selections.length;
17966 * Selects the first row in the grid.
17968 selectFirstRow : function(){
17973 * Select the last row.
17974 * @param {Boolean} keepExisting (optional) True to keep existing selections
17976 selectLastRow : function(keepExisting){
17977 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
17981 * Selects the row immediately following the last selected row.
17982 * @param {Boolean} keepExisting (optional) True to keep existing selections
17984 selectNext : function(keepExisting){
17985 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
17986 this.selectRow(this.last+1, keepExisting);
17987 this.grid.getView().focusRow(this.last);
17992 * Selects the row that precedes the last selected row.
17993 * @param {Boolean} keepExisting (optional) True to keep existing selections
17995 selectPrevious : function(keepExisting){
17997 this.selectRow(this.last-1, keepExisting);
17998 this.grid.getView().focusRow(this.last);
18003 * Returns the selected records
18004 * @return {Array} Array of selected records
18006 getSelections : function(){
18007 return [].concat(this.selections.items);
18011 * Returns the first selected record.
18014 getSelected : function(){
18015 return this.selections.itemAt(0);
18020 * Clears all selections.
18022 clearSelections : function(fast){
18023 if(this.locked) return;
18025 var ds = this.grid.dataSource;
18026 var s = this.selections;
18027 s.each(function(r){
18028 this.deselectRow(ds.indexOfId(r.id));
18032 this.selections.clear();
18039 * Selects all rows.
18041 selectAll : function(){
18042 if(this.locked) return;
18043 this.selections.clear();
18044 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18045 this.selectRow(i, true);
18050 * Returns True if there is a selection.
18051 * @return {Boolean}
18053 hasSelection : function(){
18054 return this.selections.length > 0;
18058 * Returns True if the specified row is selected.
18059 * @param {Number/Record} record The record or index of the record to check
18060 * @return {Boolean}
18062 isSelected : function(index){
18063 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18064 return (r && this.selections.key(r.id) ? true : false);
18068 * Returns True if the specified record id is selected.
18069 * @param {String} id The id of record to check
18070 * @return {Boolean}
18072 isIdSelected : function(id){
18073 return (this.selections.key(id) ? true : false);
18077 handleMouseDown : function(e, t){
18078 var view = this.grid.getView(), rowIndex;
18079 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18082 if(e.shiftKey && this.last !== false){
18083 var last = this.last;
18084 this.selectRange(last, rowIndex, e.ctrlKey);
18085 this.last = last; // reset the last
18086 view.focusRow(rowIndex);
18088 var isSelected = this.isSelected(rowIndex);
18089 if(e.button !== 0 && isSelected){
18090 view.focusRow(rowIndex);
18091 }else if(e.ctrlKey && isSelected){
18092 this.deselectRow(rowIndex);
18093 }else if(!isSelected){
18094 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18095 view.focusRow(rowIndex);
18098 this.fireEvent("afterselectionchange", this);
18101 handleDragableRowClick : function(grid, rowIndex, e)
18103 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18104 this.selectRow(rowIndex, false);
18105 grid.view.focusRow(rowIndex);
18106 this.fireEvent("afterselectionchange", this);
18111 * Selects multiple rows.
18112 * @param {Array} rows Array of the indexes of the row to select
18113 * @param {Boolean} keepExisting (optional) True to keep existing selections
18115 selectRows : function(rows, keepExisting){
18117 this.clearSelections();
18119 for(var i = 0, len = rows.length; i < len; i++){
18120 this.selectRow(rows[i], true);
18125 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18126 * @param {Number} startRow The index of the first row in the range
18127 * @param {Number} endRow The index of the last row in the range
18128 * @param {Boolean} keepExisting (optional) True to retain existing selections
18130 selectRange : function(startRow, endRow, keepExisting){
18131 if(this.locked) return;
18133 this.clearSelections();
18135 if(startRow <= endRow){
18136 for(var i = startRow; i <= endRow; i++){
18137 this.selectRow(i, true);
18140 for(var i = startRow; i >= endRow; i--){
18141 this.selectRow(i, true);
18147 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18148 * @param {Number} startRow The index of the first row in the range
18149 * @param {Number} endRow The index of the last row in the range
18151 deselectRange : function(startRow, endRow, preventViewNotify){
18152 if(this.locked) return;
18153 for(var i = startRow; i <= endRow; i++){
18154 this.deselectRow(i, preventViewNotify);
18160 * @param {Number} row The index of the row to select
18161 * @param {Boolean} keepExisting (optional) True to keep existing selections
18163 selectRow : function(index, keepExisting, preventViewNotify){
18164 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18165 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18166 if(!keepExisting || this.singleSelect){
18167 this.clearSelections();
18169 var r = this.grid.dataSource.getAt(index);
18170 this.selections.add(r);
18171 this.last = this.lastActive = index;
18172 if(!preventViewNotify){
18173 this.grid.getView().onRowSelect(index);
18175 this.fireEvent("rowselect", this, index, r);
18176 this.fireEvent("selectionchange", this);
18182 * @param {Number} row The index of the row to deselect
18184 deselectRow : function(index, preventViewNotify){
18185 if(this.locked) return;
18186 if(this.last == index){
18189 if(this.lastActive == index){
18190 this.lastActive = false;
18192 var r = this.grid.dataSource.getAt(index);
18193 this.selections.remove(r);
18194 if(!preventViewNotify){
18195 this.grid.getView().onRowDeselect(index);
18197 this.fireEvent("rowdeselect", this, index);
18198 this.fireEvent("selectionchange", this);
18202 restoreLast : function(){
18204 this.last = this._last;
18209 acceptsNav : function(row, col, cm){
18210 return !cm.isHidden(col) && cm.isCellEditable(col, row);
18214 onEditorKey : function(field, e){
18215 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18220 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18222 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18224 }else if(k == e.ENTER && !e.ctrlKey){
18228 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18230 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18232 }else if(k == e.ESC){
18236 g.startEditing(newCell[0], newCell[1]);
18241 * Ext JS Library 1.1.1
18242 * Copyright(c) 2006-2007, Ext JS, LLC.
18244 * Originally Released Under LGPL - original licence link has changed is not relivant.
18247 * <script type="text/javascript">
18251 * @class Roo.bootstrap.PagingToolbar
18253 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18255 * Create a new PagingToolbar
18256 * @param {Object} config The config object
18258 Roo.bootstrap.PagingToolbar = function(config)
18260 // old args format still supported... - xtype is prefered..
18261 // created from xtype...
18262 var ds = config.dataSource;
18263 this.toolbarItems = [];
18264 if (config.items) {
18265 this.toolbarItems = config.items;
18266 // config.items = [];
18269 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18276 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18280 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18282 * @cfg {Roo.data.Store} dataSource
18283 * The underlying data store providing the paged data
18286 * @cfg {String/HTMLElement/Element} container
18287 * container The id or element that will contain the toolbar
18290 * @cfg {Boolean} displayInfo
18291 * True to display the displayMsg (defaults to false)
18294 * @cfg {Number} pageSize
18295 * The number of records to display per page (defaults to 20)
18299 * @cfg {String} displayMsg
18300 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18302 displayMsg : 'Displaying {0} - {1} of {2}',
18304 * @cfg {String} emptyMsg
18305 * The message to display when no records are found (defaults to "No data to display")
18307 emptyMsg : 'No data to display',
18309 * Customizable piece of the default paging text (defaults to "Page")
18312 beforePageText : "Page",
18314 * Customizable piece of the default paging text (defaults to "of %0")
18317 afterPageText : "of {0}",
18319 * Customizable piece of the default paging text (defaults to "First Page")
18322 firstText : "First Page",
18324 * Customizable piece of the default paging text (defaults to "Previous Page")
18327 prevText : "Previous Page",
18329 * Customizable piece of the default paging text (defaults to "Next Page")
18332 nextText : "Next Page",
18334 * Customizable piece of the default paging text (defaults to "Last Page")
18337 lastText : "Last Page",
18339 * Customizable piece of the default paging text (defaults to "Refresh")
18342 refreshText : "Refresh",
18346 onRender : function(ct, position)
18348 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
18349 this.navgroup.parentId = this.id;
18350 this.navgroup.onRender(this.el, null);
18351 // add the buttons to the navgroup
18353 if(this.displayInfo){
18354 Roo.log(this.el.select('ul.navbar-nav',true).first());
18355 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
18356 this.displayEl = this.el.select('.x-paging-info', true).first();
18357 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
18358 // this.displayEl = navel.el.select('span',true).first();
18364 Roo.each(_this.buttons, function(e){
18365 Roo.factory(e).onRender(_this.el, null);
18369 Roo.each(_this.toolbarItems, function(e) {
18370 _this.navgroup.addItem(e);
18373 this.first = this.navgroup.addItem({
18374 tooltip: this.firstText,
18376 icon : 'fa fa-backward',
18378 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
18381 this.prev = this.navgroup.addItem({
18382 tooltip: this.prevText,
18384 icon : 'fa fa-step-backward',
18386 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
18388 //this.addSeparator();
18391 var field = this.navgroup.addItem( {
18393 cls : 'x-paging-position',
18395 html : this.beforePageText +
18396 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
18397 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
18400 this.field = field.el.select('input', true).first();
18401 this.field.on("keydown", this.onPagingKeydown, this);
18402 this.field.on("focus", function(){this.dom.select();});
18405 this.afterTextEl = field.el.select('.x-paging-after',true).first();
18406 //this.field.setHeight(18);
18407 //this.addSeparator();
18408 this.next = this.navgroup.addItem({
18409 tooltip: this.nextText,
18411 html : ' <i class="fa fa-step-forward">',
18413 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
18415 this.last = this.navgroup.addItem({
18416 tooltip: this.lastText,
18417 icon : 'fa fa-forward',
18420 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
18422 //this.addSeparator();
18423 this.loading = this.navgroup.addItem({
18424 tooltip: this.refreshText,
18425 icon: 'fa fa-refresh',
18427 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
18433 updateInfo : function(){
18434 if(this.displayEl){
18435 var count = this.ds.getCount();
18436 var msg = count == 0 ?
18440 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
18442 this.displayEl.update(msg);
18447 onLoad : function(ds, r, o){
18448 this.cursor = o.params ? o.params.start : 0;
18449 var d = this.getPageData(),
18453 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
18454 this.field.dom.value = ap;
18455 this.first.setDisabled(ap == 1);
18456 this.prev.setDisabled(ap == 1);
18457 this.next.setDisabled(ap == ps);
18458 this.last.setDisabled(ap == ps);
18459 this.loading.enable();
18464 getPageData : function(){
18465 var total = this.ds.getTotalCount();
18468 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
18469 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
18474 onLoadError : function(){
18475 this.loading.enable();
18479 onPagingKeydown : function(e){
18480 var k = e.getKey();
18481 var d = this.getPageData();
18483 var v = this.field.dom.value, pageNum;
18484 if(!v || isNaN(pageNum = parseInt(v, 10))){
18485 this.field.dom.value = d.activePage;
18488 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
18489 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
18492 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))
18494 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
18495 this.field.dom.value = pageNum;
18496 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
18499 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18501 var v = this.field.dom.value, pageNum;
18502 var increment = (e.shiftKey) ? 10 : 1;
18503 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18505 if(!v || isNaN(pageNum = parseInt(v, 10))) {
18506 this.field.dom.value = d.activePage;
18509 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
18511 this.field.dom.value = parseInt(v, 10) + increment;
18512 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
18513 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
18520 beforeLoad : function(){
18522 this.loading.disable();
18527 onClick : function(which){
18534 ds.load({params:{start: 0, limit: this.pageSize}});
18537 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
18540 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
18543 var total = ds.getTotalCount();
18544 var extra = total % this.pageSize;
18545 var lastStart = extra ? (total - extra) : total-this.pageSize;
18546 ds.load({params:{start: lastStart, limit: this.pageSize}});
18549 ds.load({params:{start: this.cursor, limit: this.pageSize}});
18555 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
18556 * @param {Roo.data.Store} store The data store to unbind
18558 unbind : function(ds){
18559 ds.un("beforeload", this.beforeLoad, this);
18560 ds.un("load", this.onLoad, this);
18561 ds.un("loadexception", this.onLoadError, this);
18562 ds.un("remove", this.updateInfo, this);
18563 ds.un("add", this.updateInfo, this);
18564 this.ds = undefined;
18568 * Binds the paging toolbar to the specified {@link Roo.data.Store}
18569 * @param {Roo.data.Store} store The data store to bind
18571 bind : function(ds){
18572 ds.on("beforeload", this.beforeLoad, this);
18573 ds.on("load", this.onLoad, this);
18574 ds.on("loadexception", this.onLoadError, this);
18575 ds.on("remove", this.updateInfo, this);
18576 ds.on("add", this.updateInfo, this);
18587 * @class Roo.bootstrap.MessageBar
18588 * @extends Roo.bootstrap.Component
18589 * Bootstrap MessageBar class
18590 * @cfg {String} html contents of the MessageBar
18591 * @cfg {String} weight (info | success | warning | danger) default info
18592 * @cfg {String} beforeClass insert the bar before the given class
18593 * @cfg {Boolean} closable (true | false) default false
18594 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
18597 * Create a new Element
18598 * @param {Object} config The config object
18601 Roo.bootstrap.MessageBar = function(config){
18602 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
18605 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
18611 beforeClass: 'bootstrap-sticky-wrap',
18613 getAutoCreate : function(){
18617 cls: 'alert alert-dismissable alert-' + this.weight,
18622 html: this.html || ''
18628 cfg.cls += ' alert-messages-fixed';
18642 onRender : function(ct, position)
18644 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
18647 var cfg = Roo.apply({}, this.getAutoCreate());
18651 cfg.cls += ' ' + this.cls;
18654 cfg.style = this.style;
18656 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
18658 this.el.setVisibilityMode(Roo.Element.DISPLAY);
18661 this.el.select('>button.close').on('click', this.hide, this);
18667 if (!this.rendered) {
18673 this.fireEvent('show', this);
18679 if (!this.rendered) {
18685 this.fireEvent('hide', this);
18688 update : function()
18690 // var e = this.el.dom.firstChild;
18692 // if(this.closable){
18693 // e = e.nextSibling;
18696 // e.data = this.html || '';
18698 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
18714 * @class Roo.bootstrap.Graph
18715 * @extends Roo.bootstrap.Component
18716 * Bootstrap Graph class
18720 @cfg {String} graphtype bar | vbar | pie
18721 @cfg {number} g_x coodinator | centre x (pie)
18722 @cfg {number} g_y coodinator | centre y (pie)
18723 @cfg {number} g_r radius (pie)
18724 @cfg {number} g_height height of the chart (respected by all elements in the set)
18725 @cfg {number} g_width width of the chart (respected by all elements in the set)
18726 @cfg {Object} title The title of the chart
18729 -opts (object) options for the chart
18731 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
18732 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
18734 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.
18735 o stacked (boolean) whether or not to tread values as in a stacked bar chart
18737 o stretch (boolean)
18739 -opts (object) options for the pie
18742 o startAngle (number)
18743 o endAngle (number)
18747 * Create a new Input
18748 * @param {Object} config The config object
18751 Roo.bootstrap.Graph = function(config){
18752 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
18758 * The img click event for the img.
18759 * @param {Roo.EventObject} e
18765 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
18776 //g_colors: this.colors,
18783 getAutoCreate : function(){
18794 onRender : function(ct,position){
18795 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
18796 this.raphael = Raphael(this.el.dom);
18798 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18799 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18800 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18801 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
18803 r.text(160, 10, "Single Series Chart").attr(txtattr);
18804 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
18805 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
18806 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
18808 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
18809 r.barchart(330, 10, 300, 220, data1);
18810 r.barchart(10, 250, 300, 220, data2, {stacked: true});
18811 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
18814 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
18815 // r.barchart(30, 30, 560, 250, xdata, {
18816 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
18817 // axis : "0 0 1 1",
18818 // axisxlabels : xdata
18819 // //yvalues : cols,
18822 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
18824 // this.load(null,xdata,{
18825 // axis : "0 0 1 1",
18826 // axisxlabels : xdata
18831 load : function(graphtype,xdata,opts){
18832 this.raphael.clear();
18834 graphtype = this.graphtype;
18839 var r = this.raphael,
18840 fin = function () {
18841 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
18843 fout = function () {
18844 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
18846 pfin = function() {
18847 this.sector.stop();
18848 this.sector.scale(1.1, 1.1, this.cx, this.cy);
18851 this.label[0].stop();
18852 this.label[0].attr({ r: 7.5 });
18853 this.label[1].attr({ "font-weight": 800 });
18856 pfout = function() {
18857 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
18860 this.label[0].animate({ r: 5 }, 500, "bounce");
18861 this.label[1].attr({ "font-weight": 400 });
18867 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
18870 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
18873 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
18874 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
18876 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
18883 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
18888 setTitle: function(o)
18893 initEvents: function() {
18896 this.el.on('click', this.onClick, this);
18900 onClick : function(e)
18902 Roo.log('img onclick');
18903 this.fireEvent('click', this, e);
18915 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
18918 * @class Roo.bootstrap.dash.NumberBox
18919 * @extends Roo.bootstrap.Component
18920 * Bootstrap NumberBox class
18921 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
18922 * @cfg {String} headline Box headline
18923 * @cfg {String} content Box content
18924 * @cfg {String} icon Box icon
18925 * @cfg {String} footer Footer text
18926 * @cfg {String} fhref Footer href
18929 * Create a new NumberBox
18930 * @param {Object} config The config object
18934 Roo.bootstrap.dash.NumberBox = function(config){
18935 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
18939 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
18949 getAutoCreate : function(){
18953 cls : 'small-box bg-' + this.bgcolor,
18961 cls : 'roo-headline',
18962 html : this.headline
18966 cls : 'roo-content',
18967 html : this.content
18981 cls : 'ion ' + this.icon
18990 cls : 'small-box-footer',
18991 href : this.fhref || '#',
18995 cfg.cn.push(footer);
19002 onRender : function(ct,position){
19003 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19010 setHeadline: function (value)
19012 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19015 setFooter: function (value, href)
19017 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19020 this.el.select('a.small-box-footer',true).first().attr('href', href);
19025 setContent: function (value)
19027 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19030 initEvents: function()
19044 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19047 * @class Roo.bootstrap.dash.TabBox
19048 * @extends Roo.bootstrap.Component
19049 * Bootstrap TabBox class
19050 * @cfg {String} title Title of the TabBox
19051 * @cfg {String} icon Icon of the TabBox
19054 * Create a new TabBox
19055 * @param {Object} config The config object
19059 Roo.bootstrap.dash.TabBox = function(config){
19060 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19065 * When a pane is added
19066 * @param {Roo.bootstrap.dash.TabPane} pane
19073 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19078 getChildContainer : function()
19080 return this.el.select('.tab-content', true).first();
19083 getAutoCreate : function(){
19087 cls: 'pull-left header',
19095 cls: 'fa ' + this.icon
19102 cls: 'nav-tabs-custom',
19106 cls: 'nav nav-tabs pull-right',
19113 cls: 'tab-content no-padding',
19121 initEvents : function()
19123 Roo.log('add add pane handler');
19124 this.on('addpane', this.onAddPane, this);
19127 * Updates the box title
19128 * @param {String} html to set the title to.
19130 setTitle : function(value)
19132 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
19134 onAddPane : function(pane)
19136 Roo.log('addpane');
19138 // tabs are rendere left to right..
19139 var ctr = this.el.select('.nav-tabs', true).first();
19142 var existing = ctr.select('.nav-tab',true);
19143 var qty = existing.getCount();;
19146 var tab = ctr.createChild({
19148 cls : 'nav-tab' + (qty ? '' : ' active'),
19156 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
19159 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
19161 pane.el.addClass('active');
19166 onTabClick : function(ev,un,ob,pane)
19168 Roo.log('tab - prev default');
19169 ev.preventDefault();
19172 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
19173 pane.tab.addClass('active');
19174 //Roo.log(pane.title);
19175 this.getChildContainer().select('.tab-pane',true).removeClass('active');
19176 // technically we should have a deactivate event.. but maybe add later.
19177 // and it should not de-activate the selected tab...
19179 pane.el.addClass('active');
19180 pane.fireEvent('activate');
19195 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19197 * @class Roo.bootstrap.TabPane
19198 * @extends Roo.bootstrap.Component
19199 * Bootstrap TabPane class
19200 * @cfg {Boolean} active (false | true) Default false
19201 * @cfg {String} title title of panel
19205 * Create a new TabPane
19206 * @param {Object} config The config object
19209 Roo.bootstrap.dash.TabPane = function(config){
19210 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19214 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
19219 // the tabBox that this is attached to.
19223 // getBox : function()
19225 // return this.el.findParent('.nav-tabs-custom', false, true);
19228 getAutoCreate : function()
19236 cfg.cls += ' active';
19241 initEvents : function()
19243 Roo.log('trigger add pane handler');
19244 this.parent().fireEvent('addpane', this)
19248 * Updates the tab title
19249 * @param {String} html to set the title to.
19251 setTitle: function(str)
19257 this.tab.select('a'.true).first().dom.innerHTML = str;
19274 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19277 * @class Roo.bootstrap.menu.Menu
19278 * @extends Roo.bootstrap.Component
19279 * Bootstrap Menu class - container for Menu
19280 * @cfg {String} html Text of the menu
19281 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19282 * @cfg {String} icon Font awesome icon
19283 * @cfg {String} pos Menu align to (top | bottom) default bottom
19287 * Create a new Menu
19288 * @param {Object} config The config object
19292 Roo.bootstrap.menu.Menu = function(config){
19293 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19297 * @event beforeshow
19298 * Fires before this menu is displayed
19299 * @param {Roo.bootstrap.menu.Menu} this
19303 * @event beforehide
19304 * Fires before this menu is hidden
19305 * @param {Roo.bootstrap.menu.Menu} this
19310 * Fires after this menu is displayed
19311 * @param {Roo.bootstrap.menu.Menu} this
19316 * Fires after this menu is hidden
19317 * @param {Roo.bootstrap.menu.Menu} this
19322 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19323 * @param {Roo.bootstrap.menu.Menu} this
19324 * @param {Roo.EventObject} e
19331 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
19335 weight : 'default',
19340 getChildContainer : function() {
19341 if(this.isSubMenu){
19345 return this.el.select('ul.dropdown-menu', true).first();
19348 getAutoCreate : function()
19353 cls : 'roo-menu-text',
19361 cls : 'fa ' + this.icon
19372 cls : 'dropdown-button btn btn-' + this.weight,
19377 cls : 'dropdown-toggle btn btn-' + this.weight,
19387 cls : 'dropdown-menu'
19393 if(this.pos == 'top'){
19394 cfg.cls += ' dropup';
19397 if(this.isSubMenu){
19400 cls : 'dropdown-menu'
19407 onRender : function(ct, position)
19409 this.isSubMenu = ct.hasClass('dropdown-submenu');
19411 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
19414 initEvents : function()
19416 if(this.isSubMenu){
19420 this.hidden = true;
19422 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
19423 this.triggerEl.on('click', this.onTriggerPress, this);
19425 this.buttonEl = this.el.select('button.dropdown-button', true).first();
19426 this.buttonEl.on('click', this.onClick, this);
19432 if(this.isSubMenu){
19436 return this.el.select('ul.dropdown-menu', true).first();
19439 onClick : function(e)
19441 this.fireEvent("click", this, e);
19444 onTriggerPress : function(e)
19446 if (this.isVisible()) {
19453 isVisible : function(){
19454 return !this.hidden;
19459 this.fireEvent("beforeshow", this);
19461 this.hidden = false;
19462 this.el.addClass('open');
19464 Roo.get(document).on("mouseup", this.onMouseUp, this);
19466 this.fireEvent("show", this);
19473 this.fireEvent("beforehide", this);
19475 this.hidden = true;
19476 this.el.removeClass('open');
19478 Roo.get(document).un("mouseup", this.onMouseUp);
19480 this.fireEvent("hide", this);
19483 onMouseUp : function()
19497 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19500 * @class Roo.bootstrap.menu.Item
19501 * @extends Roo.bootstrap.Component
19502 * Bootstrap MenuItem class
19503 * @cfg {Boolean} submenu (true | false) default false
19504 * @cfg {String} html text of the item
19505 * @cfg {String} href the link
19506 * @cfg {Boolean} disable (true | false) default false
19507 * @cfg {Boolean} preventDefault (true | false) default true
19508 * @cfg {String} icon Font awesome icon
19509 * @cfg {String} pos Submenu align to (left | right) default right
19513 * Create a new Item
19514 * @param {Object} config The config object
19518 Roo.bootstrap.menu.Item = function(config){
19519 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
19523 * Fires when the mouse is hovering over this menu
19524 * @param {Roo.bootstrap.menu.Item} this
19525 * @param {Roo.EventObject} e
19530 * Fires when the mouse exits this menu
19531 * @param {Roo.bootstrap.menu.Item} this
19532 * @param {Roo.EventObject} e
19538 * The raw click event for the entire grid.
19539 * @param {Roo.EventObject} e
19545 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
19550 preventDefault: true,
19555 getAutoCreate : function()
19560 cls : 'roo-menu-item-text',
19568 cls : 'fa ' + this.icon
19577 href : this.href || '#',
19584 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
19588 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
19590 if(this.pos == 'left'){
19591 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
19598 initEvents : function()
19600 this.el.on('mouseover', this.onMouseOver, this);
19601 this.el.on('mouseout', this.onMouseOut, this);
19603 this.el.select('a', true).first().on('click', this.onClick, this);
19607 onClick : function(e)
19609 if(this.preventDefault){
19610 e.preventDefault();
19613 this.fireEvent("click", this, e);
19616 onMouseOver : function(e)
19618 if(this.submenu && this.pos == 'left'){
19619 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
19622 this.fireEvent("mouseover", this, e);
19625 onMouseOut : function(e)
19627 this.fireEvent("mouseout", this, e);
19639 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19642 * @class Roo.bootstrap.menu.Separator
19643 * @extends Roo.bootstrap.Component
19644 * Bootstrap Separator class
19647 * Create a new Separator
19648 * @param {Object} config The config object
19652 Roo.bootstrap.menu.Separator = function(config){
19653 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
19656 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
19658 getAutoCreate : function(){