4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
21 * Do not use directly - it does not do anything..
22 * @param {Object} config The config object
27 Roo.bootstrap.Component = function(config){
28 Roo.bootstrap.Component.superclass.constructor.call(this, config);
31 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
34 allowDomMove : false, // to stop relocations in parent onRender...
42 initEvents : function() { },
48 can_build_overlaid : true,
55 // returns the parent component..
56 return Roo.ComponentMgr.get(this.parentId)
62 onRender : function(ct, position)
64 // Roo.log("Call onRender: " + this.xtype);
66 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
69 if (this.el.attr('xtype')) {
70 this.el.attr('xtypex', this.el.attr('xtype'));
71 this.el.dom.removeAttribute('xtype');
81 var cfg = Roo.apply({}, this.getAutoCreate());
84 // fill in the extra attributes
85 if (this.xattr && typeof(this.xattr) =='object') {
86 for (var i in this.xattr) {
87 cfg[i] = this.xattr[i];
92 cfg.dataId = this.dataId;
96 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
99 if (this.style) { // fixme needs to support more complex style data.
100 cfg.style = this.style;
104 cfg.name = this.name;
107 this.el = ct.createChild(cfg, position);
109 if(this.tabIndex !== undefined){
110 this.el.dom.setAttribute('tabIndex', this.tabIndex);
117 getChildContainer : function()
123 addxtype : function(tree,cntr)
127 cn = Roo.factory(tree);
129 cn.parentType = this.xtype; //??
130 cn.parentId = this.id;
132 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
134 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
136 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
138 var build_from_html = Roo.XComponent.build_from_html;
140 var is_body = (tree.xtype == 'Body') ;
142 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
144 var self_cntr_el = Roo.get(this[cntr](false));
146 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
147 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
148 return this.addxtypeChild(tree,cntr);
151 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
154 return this.addxtypeChild(Roo.apply({}, tree),cntr);
157 Roo.log('skipping render');
165 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
171 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
175 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
180 addxtypeChild : function (tree, cntr)
182 Roo.log('addxtypeChild:' + cntr);
184 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
187 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
188 (typeof(tree['flexy:foreach']) != 'undefined');
193 // render the element if it's not BODY.
194 if (tree.xtype != 'Body') {
196 cn = Roo.factory(tree);
198 cn.parentType = this.xtype; //??
199 cn.parentId = this.id;
201 var build_from_html = Roo.XComponent.build_from_html;
204 // does the container contain child eleemnts with 'xtype' attributes.
205 // that match this xtype..
206 // note - when we render we create these as well..
207 // so we should check to see if body has xtype set.
208 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
210 var self_cntr_el = Roo.get(this[cntr](false));
211 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
213 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
214 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
220 //echild.dom.removeAttribute('xtype');
222 Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
229 // if object has flexy:if - then it may or may not be rendered.
230 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
231 // skip a flexy if element.
232 Roo.log('skipping render');
235 // actually if flexy:foreach is found, we really want to create
236 // multiple copies here...
238 //Roo.log(this[cntr]());
239 cn.render(this[cntr](true));
241 // then add the element..
249 if (typeof (tree.menu) != 'undefined') {
250 tree.menu.parentType = cn.xtype;
251 tree.menu.triggerEl = cn.el;
252 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
256 if (!tree.items || !tree.items.length) {
260 var items = tree.items;
263 //Roo.log(items.length);
265 for(var i =0;i < items.length;i++) {
266 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
287 * @class Roo.bootstrap.Body
288 * @extends Roo.bootstrap.Component
289 * Bootstrap Body class
293 * @param {Object} config The config object
296 Roo.bootstrap.Body = function(config){
297 Roo.bootstrap.Body.superclass.constructor.call(this, config);
298 this.el = Roo.get(document.body);
299 if (this.cls && this.cls.length) {
300 Roo.get(document.body).addClass(this.cls);
304 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
309 onRender : function(ct, position)
311 /* Roo.log("Roo.bootstrap.Body - onRender");
312 if (this.cls && this.cls.length) {
313 Roo.get(document.body).addClass(this.cls);
333 * @class Roo.bootstrap.ButtonGroup
334 * @extends Roo.bootstrap.Component
335 * Bootstrap ButtonGroup class
336 * @cfg {String} size lg | sm | xs (default empty normal)
337 * @cfg {String} align vertical | justified (default none)
338 * @cfg {String} direction up | down (default down)
339 * @cfg {Boolean} toolbar false | true
340 * @cfg {Boolean} btn true | false
345 * @param {Object} config The config object
348 Roo.bootstrap.ButtonGroup = function(config){
349 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
352 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
360 getAutoCreate : function(){
366 cfg.html = this.html || cfg.html;
377 if (['vertical','justified'].indexOf(this.align)!==-1) {
378 cfg.cls = 'btn-group-' + this.align;
380 if (this.align == 'justified') {
381 console.log(this.items);
385 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
386 cfg.cls += ' btn-group-' + this.size;
389 if (this.direction == 'up') {
390 cfg.cls += ' dropup' ;
406 * @class Roo.bootstrap.Button
407 * @extends Roo.bootstrap.Component
408 * Bootstrap Button class
409 * @cfg {String} html The button content
410 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger | link
411 * @cfg {String} size empty | lg | sm | xs
412 * @cfg {String} tag empty | a | input | submit
413 * @cfg {String} href empty or href
414 * @cfg {Boolean} disabled false | true
415 * @cfg {Boolean} isClose false | true
416 * @cfg {String} glyphicon empty | adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out
417 * @cfg {String} badge text for badge
418 * @cfg {String} theme default (or empty) | glow
419 * @cfg {Boolean} inverse false | true
420 * @cfg {Boolean} toggle false | true
421 * @cfg {String} ontext text for on toggle state
422 * @cfg {String} offtext text for off toggle state
423 * @cfg {Boolean} defaulton true | false
424 * @cfg {Boolean} preventDefault (true | false) default true
425 * @cfg {Boolean} removeClass true | false remove the standard class..
426 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
429 * Create a new button
430 * @param {Object} config The config object
434 Roo.bootstrap.Button = function(config){
435 Roo.bootstrap.Button.superclass.constructor.call(this, config);
440 * When a butotn is pressed
441 * @param {Roo.EventObject} e
446 * After the button has been toggles
447 * @param {Roo.EventObject} e
448 * @param {boolean} pressed (also available as button.pressed)
454 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
472 preventDefault: true,
481 getAutoCreate : function(){
489 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
490 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
495 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
497 if (this.toggle == true) {
500 cls: 'slider-frame roo-button',
505 'data-off-text':'OFF',
506 cls: 'slider-button',
512 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
513 cfg.cls += ' '+this.weight;
522 cfg["aria-hidden"] = true;
524 cfg.html = "×";
530 if (this.theme==='default') {
531 cfg.cls = 'btn roo-button';
533 //if (this.parentType != 'Navbar') {
534 this.weight = this.weight.length ? this.weight : 'default';
536 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
538 cfg.cls += ' btn-' + this.weight;
540 } else if (this.theme==='glow') {
543 cfg.cls = 'btn-glow roo-button';
545 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
547 cfg.cls += ' ' + this.weight;
553 this.cls += ' inverse';
558 cfg.cls += ' active';
562 cfg.disabled = 'disabled';
566 Roo.log('changing to ul' );
568 this.glyphicon = 'caret';
571 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
573 //gsRoo.log(this.parentType);
574 if (this.parentType === 'Navbar' && !this.parent().bar) {
575 Roo.log('changing to li?');
584 href : this.href || '#'
587 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
588 cfg.cls += ' dropdown';
595 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
597 if (this.glyphicon) {
598 cfg.html = ' ' + cfg.html;
603 cls: 'glyphicon glyphicon-' + this.glyphicon
613 // cfg.cls='btn roo-button';
617 var value = cfg.html;
622 cls: 'glyphicon glyphicon-' + this.glyphicon,
641 cfg.cls += ' dropdown';
642 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
645 if (cfg.tag !== 'a' && this.href !== '') {
646 throw "Tag must be a to set href.";
647 } else if (this.href.length > 0) {
648 cfg.href = this.href;
651 if(this.removeClass){
656 cfg.target = this.target;
661 initEvents: function() {
662 // Roo.log('init events?');
663 // Roo.log(this.el.dom);
666 if (typeof (this.menu) != 'undefined') {
667 this.menu.parentType = this.xtype;
668 this.menu.triggerEl = this.el;
669 this.addxtype(Roo.apply({}, this.menu));
673 if (this.el.hasClass('roo-button')) {
674 this.el.on('click', this.onClick, this);
676 this.el.select('.roo-button').on('click', this.onClick, this);
679 if(this.removeClass){
680 this.el.on('click', this.onClick, this);
683 this.el.enableDisplayMode();
686 onClick : function(e)
692 Roo.log('button on click ');
693 if(this.preventDefault){
696 if (this.pressed === true || this.pressed === false) {
697 this.pressed = !this.pressed;
698 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
699 this.fireEvent('toggle', this, e, this.pressed);
703 this.fireEvent('click', this, e);
707 * Enables this button
711 this.disabled = false;
712 this.el.removeClass('disabled');
716 * Disable this button
720 this.disabled = true;
721 this.el.addClass('disabled');
724 * sets the active state on/off,
725 * @param {Boolean} state (optional) Force a particular state
727 setActive : function(v) {
729 this.el[v ? 'addClass' : 'removeClass']('active');
732 * toggles the current active state
734 toggleActive : function()
736 var active = this.el.hasClass('active');
737 this.setActive(!active);
741 setText : function(str)
743 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
747 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
770 * @class Roo.bootstrap.Column
771 * @extends Roo.bootstrap.Component
772 * Bootstrap Column class
773 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
774 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
775 * @cfg {Number} md colspan out of 12 for computer-sized screens
776 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
777 * @cfg {String} html content of column.
780 * Create a new Column
781 * @param {Object} config The config object
784 Roo.bootstrap.Column = function(config){
785 Roo.bootstrap.Column.superclass.constructor.call(this, config);
788 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
797 getAutoCreate : function(){
798 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
806 ['xs','sm','md','lg'].map(function(size){
807 if (settings[size]) {
808 cfg.cls += ' col-' + size + '-' + settings[size];
811 if (this.html.length) {
812 cfg.html = this.html;
831 * @class Roo.bootstrap.Container
832 * @extends Roo.bootstrap.Component
833 * Bootstrap Container class
834 * @cfg {Boolean} jumbotron is it a jumbotron element
835 * @cfg {String} html content of element
836 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
837 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
838 * @cfg {String} header content of header (for panel)
839 * @cfg {String} footer content of footer (for panel)
840 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
841 * @cfg {String} tag (header|aside|section) type of HTML tag.
845 * Create a new Container
846 * @param {Object} config The config object
849 Roo.bootstrap.Container = function(config){
850 Roo.bootstrap.Container.superclass.constructor.call(this, config);
853 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
864 getChildContainer : function() {
870 if (this.panel.length) {
871 return this.el.select('.panel-body',true).first();
878 getAutoCreate : function(){
881 tag : this.tag || 'div',
885 if (this.jumbotron) {
886 cfg.cls = 'jumbotron';
888 // - this is applied by the parent..
890 // cfg.cls = this.cls + '';
893 if (this.sticky.length) {
895 var bd = Roo.get(document.body);
896 if (!bd.hasClass('bootstrap-sticky')) {
897 bd.addClass('bootstrap-sticky');
898 Roo.select('html',true).setStyle('height', '100%');
901 cfg.cls += 'bootstrap-sticky-' + this.sticky;
905 if (this.well.length) {
909 cfg.cls +=' well well-' +this.well;
919 if (this.panel.length) {
920 cfg.cls += ' panel panel-' + this.panel;
922 if (this.header.length) {
925 cls : 'panel-heading',
941 if (this.footer.length) {
943 cls : 'panel-footer',
952 body.html = this.html || cfg.html;
954 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
955 cfg.cls = 'container';
963 if(!this.el || !this.panel.length || !this.header.length){
967 return this.el.select('.panel-title',true).first();
970 setTitle : function(v)
972 var titleEl = this.titleEl();
978 titleEl.dom.innerHTML = v;
981 getTitle : function()
984 var titleEl = this.titleEl();
990 return titleEl.dom.innerHTML;
1004 * @class Roo.bootstrap.Img
1005 * @extends Roo.bootstrap.Component
1006 * Bootstrap Img class
1007 * @cfg {Boolean} imgResponsive false | true
1008 * @cfg {String} border rounded | circle | thumbnail
1009 * @cfg {String} src image source
1010 * @cfg {String} alt image alternative text
1011 * @cfg {String} href a tag href
1012 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1015 * Create a new Input
1016 * @param {Object} config The config object
1019 Roo.bootstrap.Img = function(config){
1020 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1026 * The img click event for the img.
1027 * @param {Roo.EventObject} e
1033 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1035 imgResponsive: true,
1041 getAutoCreate : function(){
1045 cls: (this.imgResponsive) ? 'img-responsive' : '',
1049 cfg.html = this.html || cfg.html;
1051 cfg.src = this.src || cfg.src;
1053 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1054 cfg.cls += ' img-' + this.border;
1071 a.target = this.target;
1077 return (this.href) ? a : cfg;
1080 initEvents: function() {
1083 this.el.on('click', this.onClick, this);
1087 onClick : function(e)
1089 Roo.log('img onclick');
1090 this.fireEvent('click', this, e);
1104 * @class Roo.bootstrap.Link
1105 * @extends Roo.bootstrap.Component
1106 * Bootstrap Link Class
1107 * @cfg {String} alt image alternative text
1108 * @cfg {String} href a tag href
1109 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1110 * @cfg {String} html the content of the link.
1111 * @cfg {Boolean} preventDefault (true | false) default false
1115 * Create a new Input
1116 * @param {Object} config The config object
1119 Roo.bootstrap.Link = function(config){
1120 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1126 * The img click event for the img.
1127 * @param {Roo.EventObject} e
1133 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1137 preventDefault: false,
1139 getAutoCreate : function(){
1143 html : this.html || 'html-missing'
1150 cfg.href = this.href || '#';
1152 cfg.target = this.target;
1158 initEvents: function() {
1161 this.el.on('click', this.onClick, this);
1165 onClick : function(e)
1167 if(this.preventDefault){
1170 //Roo.log('img onclick');
1171 this.fireEvent('click', this, e);
1184 * @class Roo.bootstrap.Header
1185 * @extends Roo.bootstrap.Component
1186 * Bootstrap Header class
1187 * @cfg {String} html content of header
1188 * @cfg {Number} level (1|2|3|4|5|6) default 1
1191 * Create a new Header
1192 * @param {Object} config The config object
1196 Roo.bootstrap.Header = function(config){
1197 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1200 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1208 getAutoCreate : function(){
1211 tag: 'h' + (1 *this.level),
1212 html: this.html || 'fill in html'
1224 * Ext JS Library 1.1.1
1225 * Copyright(c) 2006-2007, Ext JS, LLC.
1227 * Originally Released Under LGPL - original licence link has changed is not relivant.
1230 * <script type="text/javascript">
1234 * @class Roo.bootstrap.MenuMgr
1235 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1238 Roo.bootstrap.MenuMgr = function(){
1239 var menus, active, groups = {}, attached = false, lastShow = new Date();
1241 // private - called when first menu is created
1244 active = new Roo.util.MixedCollection();
1245 Roo.get(document).addKeyListener(27, function(){
1246 if(active.length > 0){
1254 if(active && active.length > 0){
1255 var c = active.clone();
1265 if(active.length < 1){
1266 Roo.get(document).un("mouseup", onMouseDown);
1274 var last = active.last();
1275 lastShow = new Date();
1278 Roo.get(document).on("mouseup", onMouseDown);
1283 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1284 m.parentMenu.activeChild = m;
1285 }else if(last && last.isVisible()){
1286 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1291 function onBeforeHide(m){
1293 m.activeChild.hide();
1295 if(m.autoHideTimer){
1296 clearTimeout(m.autoHideTimer);
1297 delete m.autoHideTimer;
1302 function onBeforeShow(m){
1303 var pm = m.parentMenu;
1304 if(!pm && !m.allowOtherMenus){
1306 }else if(pm && pm.activeChild && active != m){
1307 pm.activeChild.hide();
1312 function onMouseDown(e){
1313 Roo.log("on MouseDown");
1314 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1322 function onBeforeCheck(mi, state){
1324 var g = groups[mi.group];
1325 for(var i = 0, l = g.length; i < l; i++){
1327 g[i].setChecked(false);
1336 * Hides all menus that are currently visible
1338 hideAll : function(){
1343 register : function(menu){
1347 menus[menu.id] = menu;
1348 menu.on("beforehide", onBeforeHide);
1349 menu.on("hide", onHide);
1350 menu.on("beforeshow", onBeforeShow);
1351 menu.on("show", onShow);
1353 if(g && menu.events["checkchange"]){
1357 groups[g].push(menu);
1358 menu.on("checkchange", onCheck);
1363 * Returns a {@link Roo.menu.Menu} object
1364 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1365 * be used to generate and return a new Menu instance.
1367 get : function(menu){
1368 if(typeof menu == "string"){ // menu id
1370 }else if(menu.events){ // menu instance
1373 /*else if(typeof menu.length == 'number'){ // array of menu items?
1374 return new Roo.bootstrap.Menu({items:menu});
1375 }else{ // otherwise, must be a config
1376 return new Roo.bootstrap.Menu(menu);
1383 unregister : function(menu){
1384 delete menus[menu.id];
1385 menu.un("beforehide", onBeforeHide);
1386 menu.un("hide", onHide);
1387 menu.un("beforeshow", onBeforeShow);
1388 menu.un("show", onShow);
1390 if(g && menu.events["checkchange"]){
1391 groups[g].remove(menu);
1392 menu.un("checkchange", onCheck);
1397 registerCheckable : function(menuItem){
1398 var g = menuItem.group;
1403 groups[g].push(menuItem);
1404 menuItem.on("beforecheckchange", onBeforeCheck);
1409 unregisterCheckable : function(menuItem){
1410 var g = menuItem.group;
1412 groups[g].remove(menuItem);
1413 menuItem.un("beforecheckchange", onBeforeCheck);
1425 * @class Roo.bootstrap.Menu
1426 * @extends Roo.bootstrap.Component
1427 * Bootstrap Menu class - container for MenuItems
1428 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1432 * @param {Object} config The config object
1436 Roo.bootstrap.Menu = function(config){
1437 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1438 if (this.registerMenu) {
1439 Roo.bootstrap.MenuMgr.register(this);
1444 * Fires before this menu is displayed
1445 * @param {Roo.menu.Menu} this
1450 * Fires before this menu is hidden
1451 * @param {Roo.menu.Menu} this
1456 * Fires after this menu is displayed
1457 * @param {Roo.menu.Menu} this
1462 * Fires after this menu is hidden
1463 * @param {Roo.menu.Menu} this
1468 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1469 * @param {Roo.menu.Menu} this
1470 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1471 * @param {Roo.EventObject} e
1476 * Fires when the mouse is hovering over this menu
1477 * @param {Roo.menu.Menu} this
1478 * @param {Roo.EventObject} e
1479 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1484 * Fires when the mouse exits this menu
1485 * @param {Roo.menu.Menu} this
1486 * @param {Roo.EventObject} e
1487 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1492 * Fires when a menu item contained in this menu is clicked
1493 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1494 * @param {Roo.EventObject} e
1498 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1501 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1505 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1508 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1510 registerMenu : true,
1512 menuItems :false, // stores the menu items..
1518 getChildContainer : function() {
1522 getAutoCreate : function(){
1524 //if (['right'].indexOf(this.align)!==-1) {
1525 // cfg.cn[1].cls += ' pull-right'
1531 cls : 'dropdown-menu' ,
1532 style : 'z-index:1000'
1536 if (this.type === 'submenu') {
1537 cfg.cls = 'submenu active';
1539 if (this.type === 'treeview') {
1540 cfg.cls = 'treeview-menu';
1545 initEvents : function() {
1547 // Roo.log("ADD event");
1548 // Roo.log(this.triggerEl.dom);
1549 this.triggerEl.on('click', this.onTriggerPress, this);
1550 this.triggerEl.addClass('dropdown-toggle');
1551 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1553 this.el.on("mouseover", this.onMouseOver, this);
1554 this.el.on("mouseout", this.onMouseOut, this);
1558 findTargetItem : function(e){
1559 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1563 //Roo.log(t); Roo.log(t.id);
1565 //Roo.log(this.menuitems);
1566 return this.menuitems.get(t.id);
1568 //return this.items.get(t.menuItemId);
1573 onClick : function(e){
1574 Roo.log("menu.onClick");
1575 var t = this.findTargetItem(e);
1581 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1582 if(t == this.activeItem && t.shouldDeactivate(e)){
1583 this.activeItem.deactivate();
1584 delete this.activeItem;
1588 this.setActiveItem(t, true);
1595 Roo.log('pass click event');
1599 this.fireEvent("click", this, t, e);
1603 onMouseOver : function(e){
1604 var t = this.findTargetItem(e);
1607 // if(t.canActivate && !t.disabled){
1608 // this.setActiveItem(t, true);
1612 this.fireEvent("mouseover", this, e, t);
1614 isVisible : function(){
1615 return !this.hidden;
1617 onMouseOut : function(e){
1618 var t = this.findTargetItem(e);
1621 // if(t == this.activeItem && t.shouldDeactivate(e)){
1622 // this.activeItem.deactivate();
1623 // delete this.activeItem;
1626 this.fireEvent("mouseout", this, e, t);
1631 * Displays this menu relative to another element
1632 * @param {String/HTMLElement/Roo.Element} element The element to align to
1633 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1634 * the element (defaults to this.defaultAlign)
1635 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1637 show : function(el, pos, parentMenu){
1638 this.parentMenu = parentMenu;
1642 this.fireEvent("beforeshow", this);
1643 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1646 * Displays this menu at a specific xy position
1647 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1648 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1650 showAt : function(xy, parentMenu, /* private: */_e){
1651 this.parentMenu = parentMenu;
1656 this.fireEvent("beforeshow", this);
1658 //xy = this.el.adjustForConstraints(xy);
1660 //this.el.setXY(xy);
1662 this.hideMenuItems();
1663 this.hidden = false;
1664 this.triggerEl.addClass('open');
1666 this.fireEvent("show", this);
1672 this.doFocus.defer(50, this);
1676 doFocus : function(){
1678 this.focusEl.focus();
1683 * Hides this menu and optionally all parent menus
1684 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1686 hide : function(deep){
1688 this.hideMenuItems();
1689 if(this.el && this.isVisible()){
1690 this.fireEvent("beforehide", this);
1691 if(this.activeItem){
1692 this.activeItem.deactivate();
1693 this.activeItem = null;
1695 this.triggerEl.removeClass('open');;
1697 this.fireEvent("hide", this);
1699 if(deep === true && this.parentMenu){
1700 this.parentMenu.hide(true);
1704 onTriggerPress : function(e)
1707 Roo.log('trigger press');
1708 //Roo.log(e.getTarget());
1709 // Roo.log(this.triggerEl.dom);
1710 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1713 if (this.isVisible()) {
1717 this.show(this.triggerEl, false, false);
1726 hideMenuItems : function()
1728 //$(backdrop).remove()
1729 Roo.select('.open',true).each(function(aa) {
1731 aa.removeClass('open');
1732 //var parent = getParent($(this))
1733 //var relatedTarget = { relatedTarget: this }
1735 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1736 //if (e.isDefaultPrevented()) return
1737 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1740 addxtypeChild : function (tree, cntr) {
1741 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1743 this.menuitems.add(comp);
1764 * @class Roo.bootstrap.MenuItem
1765 * @extends Roo.bootstrap.Component
1766 * Bootstrap MenuItem class
1767 * @cfg {String} html the menu label
1768 * @cfg {String} href the link
1769 * @cfg {Boolean} preventDefault (true | false) default true
1773 * Create a new MenuItem
1774 * @param {Object} config The config object
1778 Roo.bootstrap.MenuItem = function(config){
1779 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1784 * The raw click event for the entire grid.
1785 * @param {Roo.EventObject} e
1791 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1795 preventDefault: true,
1797 getAutoCreate : function(){
1800 cls: 'dropdown-menu-item',
1809 if (this.parent().type == 'treeview') {
1810 cfg.cls = 'treeview-menu';
1813 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1814 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1818 initEvents: function() {
1820 //this.el.select('a').on('click', this.onClick, this);
1823 onClick : function(e)
1825 Roo.log('item on click ');
1826 //if(this.preventDefault){
1827 // e.preventDefault();
1829 //this.parent().hideMenuItems();
1831 this.fireEvent('click', this, e);
1850 * @class Roo.bootstrap.MenuSeparator
1851 * @extends Roo.bootstrap.Component
1852 * Bootstrap MenuSeparator class
1855 * Create a new MenuItem
1856 * @param {Object} config The config object
1860 Roo.bootstrap.MenuSeparator = function(config){
1861 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1864 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1866 getAutoCreate : function(){
1881 <div class="modal fade">
1882 <div class="modal-dialog">
1883 <div class="modal-content">
1884 <div class="modal-header">
1885 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1886 <h4 class="modal-title">Modal title</h4>
1888 <div class="modal-body">
1889 <p>One fine body…</p>
1891 <div class="modal-footer">
1892 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1893 <button type="button" class="btn btn-primary">Save changes</button>
1895 </div><!-- /.modal-content -->
1896 </div><!-- /.modal-dialog -->
1897 </div><!-- /.modal -->
1907 * @class Roo.bootstrap.Modal
1908 * @extends Roo.bootstrap.Component
1909 * Bootstrap Modal class
1910 * @cfg {String} title Title of dialog
1911 * @cfg {Boolean} specificTitle (true|false) default false
1912 * @cfg {Array} buttons Array of buttons or standard button set..
1913 * @cfg {String} buttonPosition (left|right|center) default right
1916 * Create a new Modal Dialog
1917 * @param {Object} config The config object
1920 Roo.bootstrap.Modal = function(config){
1921 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1926 * The raw btnclick event for the button
1927 * @param {Roo.EventObject} e
1931 this.buttons = this.buttons || [];
1934 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1936 title : 'test dialog',
1943 specificTitle: false,
1945 buttonPosition: 'right',
1947 onRender : function(ct, position)
1949 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1952 var cfg = Roo.apply({}, this.getAutoCreate());
1955 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1957 //if (!cfg.name.length) {
1961 cfg.cls += ' ' + this.cls;
1964 cfg.style = this.style;
1966 this.el = Roo.get(document.body).createChild(cfg, position);
1968 //var type = this.el.dom.type;
1970 if(this.tabIndex !== undefined){
1971 this.el.dom.setAttribute('tabIndex', this.tabIndex);
1976 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1977 this.maskEl.enableDisplayMode("block");
1979 //this.el.addClass("x-dlg-modal");
1981 if (this.buttons.length) {
1982 Roo.each(this.buttons, function(bb) {
1983 b = Roo.apply({}, bb);
1984 b.xns = b.xns || Roo.bootstrap;
1985 b.xtype = b.xtype || 'Button';
1986 if (typeof(b.listeners) == 'undefined') {
1987 b.listeners = { click : this.onButtonClick.createDelegate(this) };
1990 var btn = Roo.factory(b);
1992 btn.onRender(this.el.select('.modal-footer div').first());
1996 // render the children.
1999 if(typeof(this.items) != 'undefined'){
2000 var items = this.items;
2003 for(var i =0;i < items.length;i++) {
2004 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2008 this.items = nitems;
2010 this.body = this.el.select('.modal-body',true).first();
2011 this.close = this.el.select('.modal-header .close', true).first();
2012 this.footer = this.el.select('.modal-footer',true).first();
2014 //this.el.addClass([this.fieldClass, this.cls]);
2017 getAutoCreate : function(){
2022 html : this.html || ''
2027 cls : 'modal-title',
2031 if(this.specificTitle){
2037 style : 'display: none',
2040 cls: "modal-dialog",
2043 cls : "modal-content",
2046 cls : 'modal-header',
2058 cls : 'modal-footer',
2062 cls: 'btn-' + this.buttonPosition
2081 getChildContainer : function() {
2083 return this.el.select('.modal-body',true).first();
2086 getButtonContainer : function() {
2087 return this.el.select('.modal-footer div',true).first();
2090 initEvents : function()
2092 this.el.select('.modal-header .close').on('click', this.hide, this);
2094 // this.addxtype(this);
2098 if (!this.rendered) {
2102 this.el.addClass('on');
2103 this.el.removeClass('fade');
2104 this.el.setStyle('display', 'block');
2105 Roo.get(document.body).addClass("x-body-masked");
2106 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2108 this.el.setStyle('zIndex', '10001');
2109 this.fireEvent('show', this);
2115 Roo.log('Modal hide?!');
2117 Roo.get(document.body).removeClass("x-body-masked");
2118 this.el.removeClass('on');
2119 this.el.addClass('fade');
2120 this.el.setStyle('display', 'none');
2121 this.fireEvent('hide', this);
2124 addButton : function(str, cb)
2128 var b = Roo.apply({}, { html : str } );
2129 b.xns = b.xns || Roo.bootstrap;
2130 b.xtype = b.xtype || 'Button';
2131 if (typeof(b.listeners) == 'undefined') {
2132 b.listeners = { click : cb.createDelegate(this) };
2135 var btn = Roo.factory(b);
2137 btn.onRender(this.el.select('.modal-footer div').first());
2143 setDefaultButton : function(btn)
2145 //this.el.select('.modal-footer').()
2147 resizeTo: function(w,h)
2151 setContentSize : function(w, h)
2155 onButtonClick: function(btn,e)
2158 this.fireEvent('btnclick', btn.name, e);
2160 setTitle: function(str) {
2161 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2167 Roo.apply(Roo.bootstrap.Modal, {
2169 * Button config that displays a single OK button
2178 * Button config that displays Yes and No buttons
2194 * Button config that displays OK and Cancel buttons
2209 * Button config that displays Yes, No and Cancel buttons
2231 * messagebox - can be used as a replace
2235 * @class Roo.MessageBox
2236 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2240 Roo.Msg.alert('Status', 'Changes saved successfully.');
2242 // Prompt for user data:
2243 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2245 // process text value...
2249 // Show a dialog using config options:
2251 title:'Save Changes?',
2252 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2253 buttons: Roo.Msg.YESNOCANCEL,
2260 Roo.bootstrap.MessageBox = function(){
2261 var dlg, opt, mask, waitTimer;
2262 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2263 var buttons, activeTextEl, bwidth;
2267 var handleButton = function(button){
2269 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2273 var handleHide = function(){
2275 dlg.el.removeClass(opt.cls);
2278 // Roo.TaskMgr.stop(waitTimer);
2279 // waitTimer = null;
2284 var updateButtons = function(b){
2287 buttons["ok"].hide();
2288 buttons["cancel"].hide();
2289 buttons["yes"].hide();
2290 buttons["no"].hide();
2291 //dlg.footer.dom.style.display = 'none';
2294 dlg.footer.dom.style.display = '';
2295 for(var k in buttons){
2296 if(typeof buttons[k] != "function"){
2299 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2300 width += buttons[k].el.getWidth()+15;
2310 var handleEsc = function(d, k, e){
2311 if(opt && opt.closable !== false){
2321 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2322 * @return {Roo.BasicDialog} The BasicDialog element
2324 getDialog : function(){
2326 dlg = new Roo.bootstrap.Modal( {
2329 //constraintoviewport:false,
2331 //collapsible : false,
2336 //buttonAlign:"center",
2337 closeClick : function(){
2338 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2341 handleButton("cancel");
2346 dlg.on("hide", handleHide);
2348 //dlg.addKeyListener(27, handleEsc);
2350 this.buttons = buttons;
2351 var bt = this.buttonText;
2352 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2353 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2354 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2355 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2357 bodyEl = dlg.body.createChild({
2359 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2360 '<textarea class="roo-mb-textarea"></textarea>' +
2361 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2363 msgEl = bodyEl.dom.firstChild;
2364 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2365 textboxEl.enableDisplayMode();
2366 textboxEl.addKeyListener([10,13], function(){
2367 if(dlg.isVisible() && opt && opt.buttons){
2370 }else if(opt.buttons.yes){
2371 handleButton("yes");
2375 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2376 textareaEl.enableDisplayMode();
2377 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2378 progressEl.enableDisplayMode();
2379 var pf = progressEl.dom.firstChild;
2381 pp = Roo.get(pf.firstChild);
2382 pp.setHeight(pf.offsetHeight);
2390 * Updates the message box body text
2391 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2392 * the XHTML-compliant non-breaking space character '&#160;')
2393 * @return {Roo.MessageBox} This message box
2395 updateText : function(text){
2396 if(!dlg.isVisible() && !opt.width){
2397 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2399 msgEl.innerHTML = text || ' ';
2401 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2402 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2404 Math.min(opt.width || cw , this.maxWidth),
2405 Math.max(opt.minWidth || this.minWidth, bwidth)
2408 activeTextEl.setWidth(w);
2410 if(dlg.isVisible()){
2411 dlg.fixedcenter = false;
2413 // to big, make it scroll. = But as usual stupid IE does not support
2416 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2417 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2418 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2420 bodyEl.dom.style.height = '';
2421 bodyEl.dom.style.overflowY = '';
2424 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2426 bodyEl.dom.style.overflowX = '';
2429 dlg.setContentSize(w, bodyEl.getHeight());
2430 if(dlg.isVisible()){
2431 dlg.fixedcenter = true;
2437 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2438 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2439 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2440 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2441 * @return {Roo.MessageBox} This message box
2443 updateProgress : function(value, text){
2445 this.updateText(text);
2447 if (pp) { // weird bug on my firefox - for some reason this is not defined
2448 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2454 * Returns true if the message box is currently displayed
2455 * @return {Boolean} True if the message box is visible, else false
2457 isVisible : function(){
2458 return dlg && dlg.isVisible();
2462 * Hides the message box if it is displayed
2465 if(this.isVisible()){
2471 * Displays a new message box, or reinitializes an existing message box, based on the config options
2472 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2473 * The following config object properties are supported:
2475 Property Type Description
2476 ---------- --------------- ------------------------------------------------------------------------------------
2477 animEl String/Element An id or Element from which the message box should animate as it opens and
2478 closes (defaults to undefined)
2479 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2480 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2481 closable Boolean False to hide the top-right close button (defaults to true). Note that
2482 progress and wait dialogs will ignore this property and always hide the
2483 close button as they can only be closed programmatically.
2484 cls String A custom CSS class to apply to the message box element
2485 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2486 displayed (defaults to 75)
2487 fn Function A callback function to execute after closing the dialog. The arguments to the
2488 function will be btn (the name of the button that was clicked, if applicable,
2489 e.g. "ok"), and text (the value of the active text field, if applicable).
2490 Progress and wait dialogs will ignore this option since they do not respond to
2491 user actions and can only be closed programmatically, so any required function
2492 should be called by the same code after it closes the dialog.
2493 icon String A CSS class that provides a background image to be used as an icon for
2494 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2495 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2496 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2497 modal Boolean False to allow user interaction with the page while the message box is
2498 displayed (defaults to true)
2499 msg String A string that will replace the existing message box body text (defaults
2500 to the XHTML-compliant non-breaking space character ' ')
2501 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2502 progress Boolean True to display a progress bar (defaults to false)
2503 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2504 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2505 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2506 title String The title text
2507 value String The string value to set into the active textbox element if displayed
2508 wait Boolean True to display a progress bar (defaults to false)
2509 width Number The width of the dialog in pixels
2516 msg: 'Please enter your address:',
2518 buttons: Roo.MessageBox.OKCANCEL,
2521 animEl: 'addAddressBtn'
2524 * @param {Object} config Configuration options
2525 * @return {Roo.MessageBox} This message box
2527 show : function(options)
2530 // this causes nightmares if you show one dialog after another
2531 // especially on callbacks..
2533 if(this.isVisible()){
2536 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2537 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2538 Roo.log("New Dialog Message:" + options.msg )
2539 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2540 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2543 var d = this.getDialog();
2545 d.setTitle(opt.title || " ");
2546 d.close.setDisplayed(opt.closable !== false);
2547 activeTextEl = textboxEl;
2548 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2553 textareaEl.setHeight(typeof opt.multiline == "number" ?
2554 opt.multiline : this.defaultTextHeight);
2555 activeTextEl = textareaEl;
2564 progressEl.setDisplayed(opt.progress === true);
2565 this.updateProgress(0);
2566 activeTextEl.dom.value = opt.value || "";
2568 dlg.setDefaultButton(activeTextEl);
2570 var bs = opt.buttons;
2574 }else if(bs && bs.yes){
2575 db = buttons["yes"];
2577 dlg.setDefaultButton(db);
2579 bwidth = updateButtons(opt.buttons);
2580 this.updateText(opt.msg);
2582 d.el.addClass(opt.cls);
2584 d.proxyDrag = opt.proxyDrag === true;
2585 d.modal = opt.modal !== false;
2586 d.mask = opt.modal !== false ? mask : false;
2588 // force it to the end of the z-index stack so it gets a cursor in FF
2589 document.body.appendChild(dlg.el.dom);
2590 d.animateTarget = null;
2591 d.show(options.animEl);
2597 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2598 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2599 * and closing the message box when the process is complete.
2600 * @param {String} title The title bar text
2601 * @param {String} msg The message box body text
2602 * @return {Roo.MessageBox} This message box
2604 progress : function(title, msg){
2611 minWidth: this.minProgressWidth,
2618 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2619 * If a callback function is passed it will be called after the user clicks the button, and the
2620 * id of the button that was clicked will be passed as the only parameter to the callback
2621 * (could also be the top-right close button).
2622 * @param {String} title The title bar text
2623 * @param {String} msg The message box body text
2624 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2625 * @param {Object} scope (optional) The scope of the callback function
2626 * @return {Roo.MessageBox} This message box
2628 alert : function(title, msg, fn, scope){
2641 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2642 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2643 * You are responsible for closing the message box when the process is complete.
2644 * @param {String} msg The message box body text
2645 * @param {String} title (optional) The title bar text
2646 * @return {Roo.MessageBox} This message box
2648 wait : function(msg, title){
2659 waitTimer = Roo.TaskMgr.start({
2661 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2669 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2670 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2671 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2672 * @param {String} title The title bar text
2673 * @param {String} msg The message box body text
2674 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2675 * @param {Object} scope (optional) The scope of the callback function
2676 * @return {Roo.MessageBox} This message box
2678 confirm : function(title, msg, fn, scope){
2682 buttons: this.YESNO,
2691 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2692 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2693 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2694 * (could also be the top-right close button) and the text that was entered will be passed as the two
2695 * parameters to the callback.
2696 * @param {String} title The title bar text
2697 * @param {String} msg The message box body text
2698 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2699 * @param {Object} scope (optional) The scope of the callback function
2700 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2701 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2702 * @return {Roo.MessageBox} This message box
2704 prompt : function(title, msg, fn, scope, multiline){
2708 buttons: this.OKCANCEL,
2713 multiline: multiline,
2720 * Button config that displays a single OK button
2725 * Button config that displays Yes and No buttons
2728 YESNO : {yes:true, no:true},
2730 * Button config that displays OK and Cancel buttons
2733 OKCANCEL : {ok:true, cancel:true},
2735 * Button config that displays Yes, No and Cancel buttons
2738 YESNOCANCEL : {yes:true, no:true, cancel:true},
2741 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2744 defaultTextHeight : 75,
2746 * The maximum width in pixels of the message box (defaults to 600)
2751 * The minimum width in pixels of the message box (defaults to 100)
2756 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2757 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2760 minProgressWidth : 250,
2762 * An object containing the default button text strings that can be overriden for localized language support.
2763 * Supported properties are: ok, cancel, yes and no.
2764 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2777 * Shorthand for {@link Roo.MessageBox}
2779 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2780 Roo.Msg = Roo.Msg || Roo.MessageBox;
2789 * @class Roo.bootstrap.Navbar
2790 * @extends Roo.bootstrap.Component
2791 * Bootstrap Navbar class
2794 * Create a new Navbar
2795 * @param {Object} config The config object
2799 Roo.bootstrap.Navbar = function(config){
2800 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2804 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2813 getAutoCreate : function(){
2816 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
2820 initEvents :function ()
2822 //Roo.log(this.el.select('.navbar-toggle',true));
2823 this.el.select('.navbar-toggle',true).on('click', function() {
2824 // Roo.log('click');
2825 this.el.select('.navbar-collapse',true).toggleClass('in');
2833 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2835 var size = this.el.getSize();
2836 this.maskEl.setSize(size.width, size.height);
2837 this.maskEl.enableDisplayMode("block");
2846 getChildContainer : function()
2848 if (this.el.select('.collapse').getCount()) {
2849 return this.el.select('.collapse',true).first();
2882 * @class Roo.bootstrap.NavSimplebar
2883 * @extends Roo.bootstrap.Navbar
2884 * Bootstrap Sidebar class
2886 * @cfg {Boolean} inverse is inverted color
2888 * @cfg {String} type (nav | pills | tabs)
2889 * @cfg {Boolean} arrangement stacked | justified
2890 * @cfg {String} align (left | right) alignment
2892 * @cfg {Boolean} main (true|false) main nav bar? default false
2893 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
2895 * @cfg {String} tag (header|footer|nav|div) default is nav
2901 * Create a new Sidebar
2902 * @param {Object} config The config object
2906 Roo.bootstrap.NavSimplebar = function(config){
2907 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
2910 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
2926 getAutoCreate : function(){
2930 tag : this.tag || 'div',
2943 this.type = this.type || 'nav';
2944 if (['tabs','pills'].indexOf(this.type)!==-1) {
2945 cfg.cn[0].cls += ' nav-' + this.type
2949 if (this.type!=='nav') {
2950 Roo.log('nav type must be nav/tabs/pills')
2952 cfg.cn[0].cls += ' navbar-nav'
2958 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
2959 cfg.cn[0].cls += ' nav-' + this.arrangement;
2963 if (this.align === 'right') {
2964 cfg.cn[0].cls += ' navbar-right';
2968 cfg.cls += ' navbar-inverse';
2995 * @class Roo.bootstrap.NavHeaderbar
2996 * @extends Roo.bootstrap.NavSimplebar
2997 * Bootstrap Sidebar class
2999 * @cfg {String} brand what is brand
3000 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3001 * @cfg {String} brand_href href of the brand
3002 * @cfg {Boolean} srButton generate the sr-only button (true | false) default true
3005 * Create a new Sidebar
3006 * @param {Object} config The config object
3010 Roo.bootstrap.NavHeaderbar = function(config){
3011 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3014 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3022 getAutoCreate : function(){
3025 tag: this.nav || 'nav',
3034 cls: 'navbar-header',
3039 cls: 'navbar-toggle',
3040 'data-toggle': 'collapse',
3045 html: 'Toggle navigation'
3067 cls: 'collapse navbar-collapse',
3071 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3073 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3074 cfg.cls += ' navbar-' + this.position;
3076 // tag can override this..
3078 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3081 if (this.brand !== '') {
3084 href: this.brand_href ? this.brand_href : '#',
3085 cls: 'navbar-brand',
3093 cfg.cls += ' main-nav';
3118 * @class Roo.bootstrap.NavSidebar
3119 * @extends Roo.bootstrap.Navbar
3120 * Bootstrap Sidebar class
3123 * Create a new Sidebar
3124 * @param {Object} config The config object
3128 Roo.bootstrap.NavSidebar = function(config){
3129 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3132 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3134 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3136 getAutoCreate : function(){
3141 cls: 'sidebar sidebar-nav'
3163 * @class Roo.bootstrap.NavGroup
3164 * @extends Roo.bootstrap.Component
3165 * Bootstrap NavGroup class
3166 * @cfg {String} align left | right
3167 * @cfg {Boolean} inverse false | true
3168 * @cfg {String} type (nav|pills|tab) default nav
3169 * @cfg {String} navId - reference Id for navbar.
3173 * Create a new nav group
3174 * @param {Object} config The config object
3177 Roo.bootstrap.NavGroup = function(config){
3178 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3180 Roo.bootstrap.NavGroup.register(this);
3184 * Fires when the active item changes
3185 * @param {Roo.bootstrap.NavGroup} this
3186 * @param {Roo.bootstrap.Navbar.Item} item The item selected
3187 * @param {Roo.bootstrap.Navbar.Item} item The previously selected item
3194 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3205 getAutoCreate : function()
3207 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3214 if (['tabs','pills'].indexOf(this.type)!==-1) {
3215 cfg.cls += ' nav-' + this.type
3217 if (this.type!=='nav') {
3218 Roo.log('nav type must be nav/tabs/pills')
3220 cfg.cls += ' navbar-nav'
3223 if (this.parent().sidebar) {
3226 cls: 'dashboard-menu sidebar-menu'
3232 if (this.form === true) {
3238 if (this.align === 'right') {
3239 cfg.cls += ' navbar-right';
3241 cfg.cls += ' navbar-left';
3245 if (this.align === 'right') {
3246 cfg.cls += ' navbar-right';
3250 cfg.cls += ' navbar-inverse';
3258 setActiveItem : function(item)
3261 Roo.each(this.navItems, function(v){
3266 v.setActive(false, true);
3273 item.setActive(true, true);
3274 this.fireEvent('changed', this, item, prev);
3279 addItem : function(cfg)
3281 var cn = new Roo.bootstrap.NavItem(cfg);
3283 cn.parentId = this.id;
3284 cn.onRender(this.el, null);
3288 register : function(item)
3290 this.navItems.push( item);
3291 item.navId = this.navId;
3294 getNavItem: function(tabId)
3297 Roo.each(this.navItems, function(e) {
3298 if (e.tabId == tabId) {
3314 Roo.apply(Roo.bootstrap.NavGroup, {
3318 register : function(navgrp)
3320 this.groups[navgrp.navId] = navgrp;
3323 get: function(navId) {
3324 return this.groups[navId];
3339 * @class Roo.bootstrap.NavItem
3340 * @extends Roo.bootstrap.Component
3341 * Bootstrap Navbar.NavItem class
3342 * @cfg {String} href link to
3343 * @cfg {String} html content of button
3344 * @cfg {String} badge text inside badge
3345 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3346 * @cfg {String} glyphicon name of glyphicon
3347 * @cfg {String} icon name of font awesome icon
3348 * @cfg {Boolean} active Is item active
3349 * @cfg {Boolean} disabled Is item disabled
3351 * @cfg {Boolean} preventDefault (true | false) default false
3352 * @cfg {String} tabId the tab that this item activates.
3353 * @cfg {String} tagtype (a|span) render as a href or span?
3356 * Create a new Navbar Item
3357 * @param {Object} config The config object
3359 Roo.bootstrap.NavItem = function(config){
3360 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3365 * The raw click event for the entire grid.
3366 * @param {Roo.EventObject} e
3371 * Fires when the active item active state changes
3372 * @param {Roo.bootstrap.NavItem} this
3373 * @param {boolean} state the new state
3381 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3389 preventDefault : false,
3394 getAutoCreate : function(){
3402 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3404 if (this.disabled) {
3405 cfg.cls += ' disabled';
3408 if (this.href || this.html || this.glyphicon || this.icon) {
3412 href : this.href || "#",
3413 html: this.html || ''
3418 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3421 if(this.glyphicon) {
3422 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3427 cfg.cn[0].html += " <span class='caret'></span>";
3431 if (this.badge !== '') {
3433 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3441 initEvents: function() {
3442 // Roo.log('init events?');
3443 // Roo.log(this.el.dom);
3444 if (typeof (this.menu) != 'undefined') {
3445 this.menu.parentType = this.xtype;
3446 this.menu.triggerEl = this.el;
3447 this.addxtype(Roo.apply({}, this.menu));
3451 this.el.select('a',true).on('click', this.onClick, this);
3452 // at this point parent should be available..
3453 this.parent().register(this);
3456 onClick : function(e)
3459 if(this.preventDefault){
3462 if (this.disabled) {
3465 Roo.log("fire event clicked");
3466 if(this.fireEvent('click', this, e) === false){
3470 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3471 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3472 this.parent().setActiveItem(this);
3480 isActive: function () {
3483 setActive : function(state, fire)
3485 this.active = state;
3487 this.el.removeClass('active');
3488 } else if (!this.el.hasClass('active')) {
3489 this.el.addClass('active');
3492 this.fireEvent('changed', this, state);
3497 // this should not be here...
3498 setDisabled : function(state)
3500 this.disabled = state;
3502 this.el.removeClass('disabled');
3503 } else if (!this.el.hasClass('disabled')) {
3504 this.el.addClass('disabled');
3517 * <span> icon </span>
3518 * <span> text </span>
3519 * <span>badge </span>
3523 * @class Roo.bootstrap.NavSidebarItem
3524 * @extends Roo.bootstrap.NavItem
3525 * Bootstrap Navbar.NavSidebarItem class
3527 * Create a new Navbar Button
3528 * @param {Object} config The config object
3530 Roo.bootstrap.NavSidebarItem = function(config){
3531 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3536 * The raw click event for the entire grid.
3537 * @param {Roo.EventObject} e
3542 * Fires when the active item active state changes
3543 * @param {Roo.bootstrap.NavSidebarItem} this
3544 * @param {boolean} state the new state
3552 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3555 getAutoCreate : function(){
3560 href : this.href || '#',
3572 html : this.html || ''
3577 cfg.cls += ' active';
3581 if (this.glyphicon || this.icon) {
3582 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3583 a.cn.push({ tag : 'i', cls : c }) ;
3588 if (this.badge !== '') {
3589 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3593 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3594 a.cls += 'dropdown-toggle treeview' ;
3618 * @class Roo.bootstrap.Row
3619 * @extends Roo.bootstrap.Component
3620 * Bootstrap Row class (contains columns...)
3624 * @param {Object} config The config object
3627 Roo.bootstrap.Row = function(config){
3628 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3631 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3633 getAutoCreate : function(){
3652 * @class Roo.bootstrap.Element
3653 * @extends Roo.bootstrap.Component
3654 * Bootstrap Element class
3655 * @cfg {String} html contents of the element
3656 * @cfg {String} tag tag of the element
3657 * @cfg {String} cls class of the element
3660 * Create a new Element
3661 * @param {Object} config The config object
3664 Roo.bootstrap.Element = function(config){
3665 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3668 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3675 getAutoCreate : function(){
3700 * @class Roo.bootstrap.Pagination
3701 * @extends Roo.bootstrap.Component
3702 * Bootstrap Pagination class
3703 * @cfg {String} size xs | sm | md | lg
3704 * @cfg {Boolean} inverse false | true
3707 * Create a new Pagination
3708 * @param {Object} config The config object
3711 Roo.bootstrap.Pagination = function(config){
3712 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3715 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3721 getAutoCreate : function(){
3727 cfg.cls += ' inverse';
3733 cfg.cls += " " + this.cls;
3751 * @class Roo.bootstrap.PaginationItem
3752 * @extends Roo.bootstrap.Component
3753 * Bootstrap PaginationItem class
3754 * @cfg {String} html text
3755 * @cfg {String} href the link
3756 * @cfg {Boolean} preventDefault (true | false) default true
3757 * @cfg {Boolean} active (true | false) default false
3761 * Create a new PaginationItem
3762 * @param {Object} config The config object
3766 Roo.bootstrap.PaginationItem = function(config){
3767 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3772 * The raw click event for the entire grid.
3773 * @param {Roo.EventObject} e
3779 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
3783 preventDefault: true,
3787 getAutoCreate : function(){
3793 href : this.href ? this.href : '#',
3794 html : this.html ? this.html : ''
3804 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
3810 initEvents: function() {
3812 this.el.on('click', this.onClick, this);
3815 onClick : function(e)
3817 Roo.log('PaginationItem on click ');
3818 if(this.preventDefault){
3822 this.fireEvent('click', this, e);
3838 * @class Roo.bootstrap.Slider
3839 * @extends Roo.bootstrap.Component
3840 * Bootstrap Slider class
3843 * Create a new Slider
3844 * @param {Object} config The config object
3847 Roo.bootstrap.Slider = function(config){
3848 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
3851 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
3853 getAutoCreate : function(){
3857 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
3861 cls: 'ui-slider-handle ui-state-default ui-corner-all'
3873 * Ext JS Library 1.1.1
3874 * Copyright(c) 2006-2007, Ext JS, LLC.
3876 * Originally Released Under LGPL - original licence link has changed is not relivant.
3879 * <script type="text/javascript">
3884 * @class Roo.grid.ColumnModel
3885 * @extends Roo.util.Observable
3886 * This is the default implementation of a ColumnModel used by the Grid. It defines
3887 * the columns in the grid.
3890 var colModel = new Roo.grid.ColumnModel([
3891 {header: "Ticker", width: 60, sortable: true, locked: true},
3892 {header: "Company Name", width: 150, sortable: true},
3893 {header: "Market Cap.", width: 100, sortable: true},
3894 {header: "$ Sales", width: 100, sortable: true, renderer: money},
3895 {header: "Employees", width: 100, sortable: true, resizable: false}
3900 * The config options listed for this class are options which may appear in each
3901 * individual column definition.
3902 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
3904 * @param {Object} config An Array of column config objects. See this class's
3905 * config objects for details.
3907 Roo.grid.ColumnModel = function(config){
3909 * The config passed into the constructor
3911 this.config = config;
3914 // if no id, create one
3915 // if the column does not have a dataIndex mapping,
3916 // map it to the order it is in the config
3917 for(var i = 0, len = config.length; i < len; i++){
3919 if(typeof c.dataIndex == "undefined"){
3922 if(typeof c.renderer == "string"){
3923 c.renderer = Roo.util.Format[c.renderer];
3925 if(typeof c.id == "undefined"){
3928 if(c.editor && c.editor.xtype){
3929 c.editor = Roo.factory(c.editor, Roo.grid);
3931 if(c.editor && c.editor.isFormField){
3932 c.editor = new Roo.grid.GridEditor(c.editor);
3934 this.lookup[c.id] = c;
3938 * The width of columns which have no width specified (defaults to 100)
3941 this.defaultWidth = 100;
3944 * Default sortable of columns which have no sortable specified (defaults to false)
3947 this.defaultSortable = false;
3951 * @event widthchange
3952 * Fires when the width of a column changes.
3953 * @param {ColumnModel} this
3954 * @param {Number} columnIndex The column index
3955 * @param {Number} newWidth The new width
3957 "widthchange": true,
3959 * @event headerchange
3960 * Fires when the text of a header changes.
3961 * @param {ColumnModel} this
3962 * @param {Number} columnIndex The column index
3963 * @param {Number} newText The new header text
3965 "headerchange": true,
3967 * @event hiddenchange
3968 * Fires when a column is hidden or "unhidden".
3969 * @param {ColumnModel} this
3970 * @param {Number} columnIndex The column index
3971 * @param {Boolean} hidden true if hidden, false otherwise
3973 "hiddenchange": true,
3975 * @event columnmoved
3976 * Fires when a column is moved.
3977 * @param {ColumnModel} this
3978 * @param {Number} oldIndex
3979 * @param {Number} newIndex
3981 "columnmoved" : true,
3983 * @event columlockchange
3984 * Fires when a column's locked state is changed
3985 * @param {ColumnModel} this
3986 * @param {Number} colIndex
3987 * @param {Boolean} locked true if locked
3989 "columnlockchange" : true
3991 Roo.grid.ColumnModel.superclass.constructor.call(this);
3993 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
3995 * @cfg {String} header The header text to display in the Grid view.
3998 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
3999 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4000 * specified, the column's index is used as an index into the Record's data Array.
4003 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4004 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4007 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4008 * Defaults to the value of the {@link #defaultSortable} property.
4009 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4012 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4015 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4018 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4021 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4024 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4025 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4026 * default renderer uses the raw data value.
4029 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4032 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4036 * Returns the id of the column at the specified index.
4037 * @param {Number} index The column index
4038 * @return {String} the id
4040 getColumnId : function(index){
4041 return this.config[index].id;
4045 * Returns the column for a specified id.
4046 * @param {String} id The column id
4047 * @return {Object} the column
4049 getColumnById : function(id){
4050 return this.lookup[id];
4055 * Returns the column for a specified dataIndex.
4056 * @param {String} dataIndex The column dataIndex
4057 * @return {Object|Boolean} the column or false if not found
4059 getColumnByDataIndex: function(dataIndex){
4060 var index = this.findColumnIndex(dataIndex);
4061 return index > -1 ? this.config[index] : false;
4065 * Returns the index for a specified column id.
4066 * @param {String} id The column id
4067 * @return {Number} the index, or -1 if not found
4069 getIndexById : function(id){
4070 for(var i = 0, len = this.config.length; i < len; i++){
4071 if(this.config[i].id == id){
4079 * Returns the index for a specified column dataIndex.
4080 * @param {String} dataIndex The column dataIndex
4081 * @return {Number} the index, or -1 if not found
4084 findColumnIndex : function(dataIndex){
4085 for(var i = 0, len = this.config.length; i < len; i++){
4086 if(this.config[i].dataIndex == dataIndex){
4094 moveColumn : function(oldIndex, newIndex){
4095 var c = this.config[oldIndex];
4096 this.config.splice(oldIndex, 1);
4097 this.config.splice(newIndex, 0, c);
4098 this.dataMap = null;
4099 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4102 isLocked : function(colIndex){
4103 return this.config[colIndex].locked === true;
4106 setLocked : function(colIndex, value, suppressEvent){
4107 if(this.isLocked(colIndex) == value){
4110 this.config[colIndex].locked = value;
4112 this.fireEvent("columnlockchange", this, colIndex, value);
4116 getTotalLockedWidth : function(){
4118 for(var i = 0; i < this.config.length; i++){
4119 if(this.isLocked(i) && !this.isHidden(i)){
4120 this.totalWidth += this.getColumnWidth(i);
4126 getLockedCount : function(){
4127 for(var i = 0, len = this.config.length; i < len; i++){
4128 if(!this.isLocked(i)){
4135 * Returns the number of columns.
4138 getColumnCount : function(visibleOnly){
4139 if(visibleOnly === true){
4141 for(var i = 0, len = this.config.length; i < len; i++){
4142 if(!this.isHidden(i)){
4148 return this.config.length;
4152 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4153 * @param {Function} fn
4154 * @param {Object} scope (optional)
4155 * @return {Array} result
4157 getColumnsBy : function(fn, scope){
4159 for(var i = 0, len = this.config.length; i < len; i++){
4160 var c = this.config[i];
4161 if(fn.call(scope||this, c, i) === true){
4169 * Returns true if the specified column is sortable.
4170 * @param {Number} col The column index
4173 isSortable : function(col){
4174 if(typeof this.config[col].sortable == "undefined"){
4175 return this.defaultSortable;
4177 return this.config[col].sortable;
4181 * Returns the rendering (formatting) function defined for the column.
4182 * @param {Number} col The column index.
4183 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4185 getRenderer : function(col){
4186 if(!this.config[col].renderer){
4187 return Roo.grid.ColumnModel.defaultRenderer;
4189 return this.config[col].renderer;
4193 * Sets the rendering (formatting) function for a column.
4194 * @param {Number} col The column index
4195 * @param {Function} fn The function to use to process the cell's raw data
4196 * to return HTML markup for the grid view. The render function is called with
4197 * the following parameters:<ul>
4198 * <li>Data value.</li>
4199 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4200 * <li>css A CSS style string to apply to the table cell.</li>
4201 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4202 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4203 * <li>Row index</li>
4204 * <li>Column index</li>
4205 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4207 setRenderer : function(col, fn){
4208 this.config[col].renderer = fn;
4212 * Returns the width for the specified column.
4213 * @param {Number} col The column index
4216 getColumnWidth : function(col){
4217 return this.config[col].width * 1 || this.defaultWidth;
4221 * Sets the width for a column.
4222 * @param {Number} col The column index
4223 * @param {Number} width The new width
4225 setColumnWidth : function(col, width, suppressEvent){
4226 this.config[col].width = width;
4227 this.totalWidth = null;
4229 this.fireEvent("widthchange", this, col, width);
4234 * Returns the total width of all columns.
4235 * @param {Boolean} includeHidden True to include hidden column widths
4238 getTotalWidth : function(includeHidden){
4239 if(!this.totalWidth){
4240 this.totalWidth = 0;
4241 for(var i = 0, len = this.config.length; i < len; i++){
4242 if(includeHidden || !this.isHidden(i)){
4243 this.totalWidth += this.getColumnWidth(i);
4247 return this.totalWidth;
4251 * Returns the header for the specified column.
4252 * @param {Number} col The column index
4255 getColumnHeader : function(col){
4256 return this.config[col].header;
4260 * Sets the header for a column.
4261 * @param {Number} col The column index
4262 * @param {String} header The new header
4264 setColumnHeader : function(col, header){
4265 this.config[col].header = header;
4266 this.fireEvent("headerchange", this, col, header);
4270 * Returns the tooltip for the specified column.
4271 * @param {Number} col The column index
4274 getColumnTooltip : function(col){
4275 return this.config[col].tooltip;
4278 * Sets the tooltip for a column.
4279 * @param {Number} col The column index
4280 * @param {String} tooltip The new tooltip
4282 setColumnTooltip : function(col, tooltip){
4283 this.config[col].tooltip = tooltip;
4287 * Returns the dataIndex for the specified column.
4288 * @param {Number} col The column index
4291 getDataIndex : function(col){
4292 return this.config[col].dataIndex;
4296 * Sets the dataIndex for a column.
4297 * @param {Number} col The column index
4298 * @param {Number} dataIndex The new dataIndex
4300 setDataIndex : function(col, dataIndex){
4301 this.config[col].dataIndex = dataIndex;
4307 * Returns true if the cell is editable.
4308 * @param {Number} colIndex The column index
4309 * @param {Number} rowIndex The row index
4312 isCellEditable : function(colIndex, rowIndex){
4313 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4317 * Returns the editor defined for the cell/column.
4318 * return false or null to disable editing.
4319 * @param {Number} colIndex The column index
4320 * @param {Number} rowIndex The row index
4323 getCellEditor : function(colIndex, rowIndex){
4324 return this.config[colIndex].editor;
4328 * Sets if a column is editable.
4329 * @param {Number} col The column index
4330 * @param {Boolean} editable True if the column is editable
4332 setEditable : function(col, editable){
4333 this.config[col].editable = editable;
4338 * Returns true if the column is hidden.
4339 * @param {Number} colIndex The column index
4342 isHidden : function(colIndex){
4343 return this.config[colIndex].hidden;
4348 * Returns true if the column width cannot be changed
4350 isFixed : function(colIndex){
4351 return this.config[colIndex].fixed;
4355 * Returns true if the column can be resized
4358 isResizable : function(colIndex){
4359 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4362 * Sets if a column is hidden.
4363 * @param {Number} colIndex The column index
4364 * @param {Boolean} hidden True if the column is hidden
4366 setHidden : function(colIndex, hidden){
4367 this.config[colIndex].hidden = hidden;
4368 this.totalWidth = null;
4369 this.fireEvent("hiddenchange", this, colIndex, hidden);
4373 * Sets the editor for a column.
4374 * @param {Number} col The column index
4375 * @param {Object} editor The editor object
4377 setEditor : function(col, editor){
4378 this.config[col].editor = editor;
4382 Roo.grid.ColumnModel.defaultRenderer = function(value){
4383 if(typeof value == "string" && value.length < 1){
4389 // Alias for backwards compatibility
4390 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4393 * Ext JS Library 1.1.1
4394 * Copyright(c) 2006-2007, Ext JS, LLC.
4396 * Originally Released Under LGPL - original licence link has changed is not relivant.
4399 * <script type="text/javascript">
4403 * @class Roo.LoadMask
4404 * A simple utility class for generically masking elements while loading data. If the element being masked has
4405 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4406 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4407 * element's UpdateManager load indicator and will be destroyed after the initial load.
4409 * Create a new LoadMask
4410 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4411 * @param {Object} config The config object
4413 Roo.LoadMask = function(el, config){
4414 this.el = Roo.get(el);
4415 Roo.apply(this, config);
4417 this.store.on('beforeload', this.onBeforeLoad, this);
4418 this.store.on('load', this.onLoad, this);
4419 this.store.on('loadexception', this.onLoadException, this);
4420 this.removeMask = false;
4422 var um = this.el.getUpdateManager();
4423 um.showLoadIndicator = false; // disable the default indicator
4424 um.on('beforeupdate', this.onBeforeLoad, this);
4425 um.on('update', this.onLoad, this);
4426 um.on('failure', this.onLoad, this);
4427 this.removeMask = true;
4431 Roo.LoadMask.prototype = {
4433 * @cfg {Boolean} removeMask
4434 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4435 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4439 * The text to display in a centered loading message box (defaults to 'Loading...')
4443 * @cfg {String} msgCls
4444 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4446 msgCls : 'x-mask-loading',
4449 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4455 * Disables the mask to prevent it from being displayed
4457 disable : function(){
4458 this.disabled = true;
4462 * Enables the mask so that it can be displayed
4464 enable : function(){
4465 this.disabled = false;
4468 onLoadException : function()
4472 if (typeof(arguments[3]) != 'undefined') {
4473 Roo.MessageBox.alert("Error loading",arguments[3]);
4477 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4478 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4487 this.el.unmask(this.removeMask);
4492 this.el.unmask(this.removeMask);
4496 onBeforeLoad : function(){
4498 this.el.mask(this.msg, this.msgCls);
4503 destroy : function(){
4505 this.store.un('beforeload', this.onBeforeLoad, this);
4506 this.store.un('load', this.onLoad, this);
4507 this.store.un('loadexception', this.onLoadException, this);
4509 var um = this.el.getUpdateManager();
4510 um.un('beforeupdate', this.onBeforeLoad, this);
4511 um.un('update', this.onLoad, this);
4512 um.un('failure', this.onLoad, this);
4523 * @class Roo.bootstrap.Table
4524 * @extends Roo.bootstrap.Component
4525 * Bootstrap Table class
4526 * @cfg {String} cls table class
4527 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4528 * @cfg {String} bgcolor Specifies the background color for a table
4529 * @cfg {Number} border Specifies whether the table cells should have borders or not
4530 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4531 * @cfg {Number} cellspacing Specifies the space between cells
4532 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4533 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4534 * @cfg {String} sortable Specifies that the table should be sortable
4535 * @cfg {String} summary Specifies a summary of the content of a table
4536 * @cfg {Number} width Specifies the width of a table
4537 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4539 * @cfg {boolean} striped Should the rows be alternative striped
4540 * @cfg {boolean} bordered Add borders to the table
4541 * @cfg {boolean} hover Add hover highlighting
4542 * @cfg {boolean} condensed Format condensed
4543 * @cfg {boolean} responsive Format condensed
4544 * @cfg {Boolean} loadMask (true|false) default false
4545 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4546 * @cfg {Boolean} thead (true|false) generate thead, default true
4547 * @cfg {Boolean} RowSelection (true|false) default false
4548 * @cfg {Boolean} CellSelection (true|false) default false
4550 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4554 * Create a new Table
4555 * @param {Object} config The config object
4558 Roo.bootstrap.Table = function(config){
4559 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4562 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4563 this.sm = this.selModel;
4564 this.sm.xmodule = this.xmodule || false;
4566 if (this.cm && typeof(this.cm.config) == 'undefined') {
4567 this.colModel = new Roo.grid.ColumnModel(this.cm);
4568 this.cm = this.colModel;
4569 this.cm.xmodule = this.xmodule || false;
4572 this.store= Roo.factory(this.store, Roo.data);
4573 this.ds = this.store;
4574 this.ds.xmodule = this.xmodule || false;
4577 if (this.footer && this.store) {
4578 this.footer.dataSource = this.ds;
4579 this.footer = Roo.factory(this.footer);
4586 * Fires when a cell is clicked
4587 * @param {Roo.bootstrap.Table} this
4588 * @param {Roo.Element} el
4589 * @param {Number} rowIndex
4590 * @param {Number} columnIndex
4591 * @param {Roo.EventObject} e
4595 * @event celldblclick
4596 * Fires when a cell is double clicked
4597 * @param {Roo.bootstrap.Table} this
4598 * @param {Roo.Element} el
4599 * @param {Number} rowIndex
4600 * @param {Number} columnIndex
4601 * @param {Roo.EventObject} e
4603 "celldblclick" : true,
4606 * Fires when a row is clicked
4607 * @param {Roo.bootstrap.Table} this
4608 * @param {Roo.Element} el
4609 * @param {Number} rowIndex
4610 * @param {Roo.EventObject} e
4614 * @event rowdblclick
4615 * Fires when a row is double clicked
4616 * @param {Roo.bootstrap.Table} this
4617 * @param {Roo.Element} el
4618 * @param {Number} rowIndex
4619 * @param {Roo.EventObject} e
4621 "rowdblclick" : true,
4624 * Fires when a mouseover occur
4625 * @param {Roo.bootstrap.Table} this
4626 * @param {Roo.Element} el
4627 * @param {Number} rowIndex
4628 * @param {Number} columnIndex
4629 * @param {Roo.EventObject} e
4634 * Fires when a mouseout occur
4635 * @param {Roo.bootstrap.Table} this
4636 * @param {Roo.Element} el
4637 * @param {Number} rowIndex
4638 * @param {Number} columnIndex
4639 * @param {Roo.EventObject} e
4644 * Fires when a row is rendered, so you can change add a style to it.
4645 * @param {Roo.bootstrap.Table} this
4646 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
4651 * Fires when record have been loaded
4652 * @param {Roo.bootstrap.Table} this
4653 * @param {Object} records store records
4660 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4684 RowSelection : false,
4685 CellSelection : false,
4689 getAutoCreate : function(){
4690 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4699 cfg.cls += ' table-striped';
4703 cfg.cls += ' table-hover';
4705 if (this.bordered) {
4706 cfg.cls += ' table-bordered';
4708 if (this.condensed) {
4709 cfg.cls += ' table-condensed';
4711 if (this.responsive) {
4712 cfg.cls += ' table-responsive';
4716 cfg.cls+= ' ' +this.cls;
4719 // this lot should be simplifed...
4722 cfg.align=this.align;
4725 cfg.bgcolor=this.bgcolor;
4728 cfg.border=this.border;
4730 if (this.cellpadding) {
4731 cfg.cellpadding=this.cellpadding;
4733 if (this.cellspacing) {
4734 cfg.cellspacing=this.cellspacing;
4737 cfg.frame=this.frame;
4740 cfg.rules=this.rules;
4742 if (this.sortable) {
4743 cfg.sortable=this.sortable;
4746 cfg.summary=this.summary;
4749 cfg.width=this.width;
4752 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
4755 if(this.store || this.cm){
4757 cfg.cn.push(this.renderHeader());
4760 cfg.cn.push(this.renderBody());
4763 cfg.cn.push(this.renderFooter());
4766 cfg.cls+= ' TableGrid';
4769 return { cn : [ cfg ] };
4772 initEvents : function()
4774 if(!this.store || !this.cm){
4778 Roo.log('initEvents with ds!!!!');
4782 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4783 e.on('click', _this.sort, _this);
4786 this.el.on("click", this.onClick, this);
4787 this.el.on("dblclick", this.onDblClick, this);
4789 this.parent().el.setStyle('position', 'relative');
4791 this.footer.parentId = this.id;
4792 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
4795 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
4797 this.store.on('load', this.onLoad, this);
4798 this.store.on('beforeload', this.onBeforeLoad, this);
4802 onMouseover : function(e, el)
4804 var cell = Roo.get(el);
4810 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4811 cell = cell.findParent('td', false, true);
4814 var row = cell.findParent('tr', false, true);
4815 var cellIndex = cell.dom.cellIndex;
4816 var rowIndex = row.dom.rowIndex - 1; // start from 0
4818 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
4822 onMouseout : function(e, el)
4824 var cell = Roo.get(el);
4830 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4831 cell = cell.findParent('td', false, true);
4834 var row = cell.findParent('tr', false, true);
4835 var cellIndex = cell.dom.cellIndex;
4836 var rowIndex = row.dom.rowIndex - 1; // start from 0
4838 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
4842 onClick : function(e, el)
4844 var cell = Roo.get(el);
4846 if(!cell || !this.CellSelection || !this.RowSelection){
4851 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4852 cell = cell.findParent('td', false, true);
4855 var row = cell.findParent('tr', false, true);
4856 var cellIndex = cell.dom.cellIndex;
4857 var rowIndex = row.dom.rowIndex - 1;
4859 if(this.CellSelection){
4860 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
4863 if(this.RowSelection){
4864 this.fireEvent('rowclick', this, row, rowIndex, e);
4870 onDblClick : function(e,el)
4872 var cell = Roo.get(el);
4874 if(!cell || !this.CellSelection || !this.RowSelection){
4878 if(e.getTarget().nodeName.toLowerCase() != 'td'){
4879 cell = cell.findParent('td', false, true);
4882 var row = cell.findParent('tr', false, true);
4883 var cellIndex = cell.dom.cellIndex;
4884 var rowIndex = row.dom.rowIndex - 1;
4886 if(this.CellSelection){
4887 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
4890 if(this.RowSelection){
4891 this.fireEvent('rowdblclick', this, row, rowIndex, e);
4895 sort : function(e,el)
4897 var col = Roo.get(el)
4899 if(!col.hasClass('sortable')){
4903 var sort = col.attr('sort');
4906 if(col.hasClass('glyphicon-arrow-up')){
4910 this.store.sortInfo = {field : sort, direction : dir};
4913 Roo.log("calling footer first");
4914 this.footer.onClick('first');
4917 this.store.load({ params : { start : 0 } });
4921 renderHeader : function()
4930 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4932 var config = cm.config[i];
4937 html: cm.getColumnHeader(i)
4940 if(typeof(config.hidden) != 'undefined' && config.hidden){
4941 c.style += ' display:none;';
4944 if(typeof(config.dataIndex) != 'undefined'){
4945 c.sort = config.dataIndex;
4948 if(typeof(config.sortable) != 'undefined' && config.sortable){
4952 // if(typeof(config.align) != 'undefined' && config.align.length){
4953 // c.style += ' text-align:' + config.align + ';';
4956 if(typeof(config.width) != 'undefined'){
4957 c.style += ' width:' + config.width + 'px;';
4966 renderBody : function()
4976 colspan : this.cm.getColumnCount()
4986 renderFooter : function()
4996 colspan : this.cm.getColumnCount()
5008 Roo.log('ds onload');
5014 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5015 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5017 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5018 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5021 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5022 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5026 var tbody = this.el.select('tbody', true).first();
5030 if(this.store.getCount() > 0){
5031 this.store.data.each(function(d,rowIndex){
5037 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5038 var config = cm.config[i];
5040 var renderer = cm.getRenderer(i);
5044 if(typeof(renderer) !== 'undefined'){
5045 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5048 if(typeof(value) === 'object'){
5057 rowIndex : rowIndex,
5062 _this.fireEvent('rowclass', this, rowcfg);
5067 cls : rowcfg.rowClass,
5069 html: (typeof(value) === 'object') ? '' : value
5072 if(typeof(config.hidden) != 'undefined' && config.hidden){
5073 td.style += ' display:none;';
5076 if(typeof(config.align) != 'undefined' && config.align.length){
5077 td.style += ' text-align:' + config.align + ';';
5080 if(typeof(config.width) != 'undefined'){
5081 td.style += ' width:' + config.width + 'px;';
5089 tbody.createChild(row);
5097 Roo.each(renders, function(r){
5098 _this.renderColumn(r);
5102 Roo.each(this.el.select('tbody td', true).elements, function(e){
5103 e.on('mouseover', _this.onMouseover, _this);
5106 Roo.each(this.el.select('tbody td', true).elements, function(e){
5107 e.on('mouseout', _this.onMouseout, _this);
5110 this.fireEvent('afterload', this, this.store.data);
5111 //if(this.loadMask){
5112 // this.maskEl.hide();
5116 onBeforeLoad : function()
5118 //Roo.log('ds onBeforeLoad');
5122 //if(this.loadMask){
5123 // this.maskEl.show();
5129 this.el.select('tbody', true).first().dom.innerHTML = '';
5132 getSelectionModel : function(){
5134 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5136 return this.selModel;
5139 renderColumn : function(r)
5143 var t = r.cfg.render(r.container);
5146 Roo.each(r.cfg.cn, function(c){
5148 container: t.getChildContainer(),
5151 _this.renderColumn(child);
5168 * @class Roo.bootstrap.TableCell
5169 * @extends Roo.bootstrap.Component
5170 * Bootstrap TableCell class
5171 * @cfg {String} html cell contain text
5172 * @cfg {String} cls cell class
5173 * @cfg {String} tag cell tag (td|th) default td
5174 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5175 * @cfg {String} align Aligns the content in a cell
5176 * @cfg {String} axis Categorizes cells
5177 * @cfg {String} bgcolor Specifies the background color of a cell
5178 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5179 * @cfg {Number} colspan Specifies the number of columns a cell should span
5180 * @cfg {String} headers Specifies one or more header cells a cell is related to
5181 * @cfg {Number} height Sets the height of a cell
5182 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5183 * @cfg {Number} rowspan Sets the number of rows a cell should span
5184 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5185 * @cfg {String} valign Vertical aligns the content in a cell
5186 * @cfg {Number} width Specifies the width of a cell
5189 * Create a new TableCell
5190 * @param {Object} config The config object
5193 Roo.bootstrap.TableCell = function(config){
5194 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5197 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5217 getAutoCreate : function(){
5218 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5238 cfg.align=this.align
5244 cfg.bgcolor=this.bgcolor
5247 cfg.charoff=this.charoff
5250 cfg.colspan=this.colspan
5253 cfg.headers=this.headers
5256 cfg.height=this.height
5259 cfg.nowrap=this.nowrap
5262 cfg.rowspan=this.rowspan
5265 cfg.scope=this.scope
5268 cfg.valign=this.valign
5271 cfg.width=this.width
5290 * @class Roo.bootstrap.TableRow
5291 * @extends Roo.bootstrap.Component
5292 * Bootstrap TableRow class
5293 * @cfg {String} cls row class
5294 * @cfg {String} align Aligns the content in a table row
5295 * @cfg {String} bgcolor Specifies a background color for a table row
5296 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5297 * @cfg {String} valign Vertical aligns the content in a table row
5300 * Create a new TableRow
5301 * @param {Object} config The config object
5304 Roo.bootstrap.TableRow = function(config){
5305 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5308 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5316 getAutoCreate : function(){
5317 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5327 cfg.align = this.align;
5330 cfg.bgcolor = this.bgcolor;
5333 cfg.charoff = this.charoff;
5336 cfg.valign = this.valign;
5354 * @class Roo.bootstrap.TableBody
5355 * @extends Roo.bootstrap.Component
5356 * Bootstrap TableBody class
5357 * @cfg {String} cls element class
5358 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5359 * @cfg {String} align Aligns the content inside the element
5360 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5361 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5364 * Create a new TableBody
5365 * @param {Object} config The config object
5368 Roo.bootstrap.TableBody = function(config){
5369 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5372 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5380 getAutoCreate : function(){
5381 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5395 cfg.align = this.align;
5398 cfg.charoff = this.charoff;
5401 cfg.valign = this.valign;
5408 // initEvents : function()
5415 // this.store = Roo.factory(this.store, Roo.data);
5416 // this.store.on('load', this.onLoad, this);
5418 // this.store.load();
5422 // onLoad: function ()
5424 // this.fireEvent('load', this);
5434 * Ext JS Library 1.1.1
5435 * Copyright(c) 2006-2007, Ext JS, LLC.
5437 * Originally Released Under LGPL - original licence link has changed is not relivant.
5440 * <script type="text/javascript">
5443 // as we use this in bootstrap.
5444 Roo.namespace('Roo.form');
5446 * @class Roo.form.Action
5447 * Internal Class used to handle form actions
5449 * @param {Roo.form.BasicForm} el The form element or its id
5450 * @param {Object} config Configuration options
5455 // define the action interface
5456 Roo.form.Action = function(form, options){
5458 this.options = options || {};
5461 * Client Validation Failed
5464 Roo.form.Action.CLIENT_INVALID = 'client';
5466 * Server Validation Failed
5469 Roo.form.Action.SERVER_INVALID = 'server';
5471 * Connect to Server Failed
5474 Roo.form.Action.CONNECT_FAILURE = 'connect';
5476 * Reading Data from Server Failed
5479 Roo.form.Action.LOAD_FAILURE = 'load';
5481 Roo.form.Action.prototype = {
5483 failureType : undefined,
5484 response : undefined,
5488 run : function(options){
5493 success : function(response){
5498 handleResponse : function(response){
5502 // default connection failure
5503 failure : function(response){
5505 this.response = response;
5506 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5507 this.form.afterAction(this, false);
5510 processResponse : function(response){
5511 this.response = response;
5512 if(!response.responseText){
5515 this.result = this.handleResponse(response);
5519 // utility functions used internally
5520 getUrl : function(appendParams){
5521 var url = this.options.url || this.form.url || this.form.el.dom.action;
5523 var p = this.getParams();
5525 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5531 getMethod : function(){
5532 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5535 getParams : function(){
5536 var bp = this.form.baseParams;
5537 var p = this.options.params;
5539 if(typeof p == "object"){
5540 p = Roo.urlEncode(Roo.applyIf(p, bp));
5541 }else if(typeof p == 'string' && bp){
5542 p += '&' + Roo.urlEncode(bp);
5545 p = Roo.urlEncode(bp);
5550 createCallback : function(){
5552 success: this.success,
5553 failure: this.failure,
5555 timeout: (this.form.timeout*1000),
5556 upload: this.form.fileUpload ? this.success : undefined
5561 Roo.form.Action.Submit = function(form, options){
5562 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
5565 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
5568 haveProgress : false,
5569 uploadComplete : false,
5571 // uploadProgress indicator.
5572 uploadProgress : function()
5574 if (!this.form.progressUrl) {
5578 if (!this.haveProgress) {
5579 Roo.MessageBox.progress("Uploading", "Uploading");
5581 if (this.uploadComplete) {
5582 Roo.MessageBox.hide();
5586 this.haveProgress = true;
5588 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
5590 var c = new Roo.data.Connection();
5592 url : this.form.progressUrl,
5597 success : function(req){
5598 //console.log(data);
5602 rdata = Roo.decode(req.responseText)
5604 Roo.log("Invalid data from server..");
5608 if (!rdata || !rdata.success) {
5610 Roo.MessageBox.alert(Roo.encode(rdata));
5613 var data = rdata.data;
5615 if (this.uploadComplete) {
5616 Roo.MessageBox.hide();
5621 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
5622 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
5625 this.uploadProgress.defer(2000,this);
5628 failure: function(data) {
5629 Roo.log('progress url failed ');
5640 // run get Values on the form, so it syncs any secondary forms.
5641 this.form.getValues();
5643 var o = this.options;
5644 var method = this.getMethod();
5645 var isPost = method == 'POST';
5646 if(o.clientValidation === false || this.form.isValid()){
5648 if (this.form.progressUrl) {
5649 this.form.findField('UPLOAD_IDENTIFIER').setValue(
5650 (new Date() * 1) + '' + Math.random());
5655 Roo.Ajax.request(Roo.apply(this.createCallback(), {
5656 form:this.form.el.dom,
5657 url:this.getUrl(!isPost),
5659 params:isPost ? this.getParams() : null,
5660 isUpload: this.form.fileUpload
5663 this.uploadProgress();
5665 }else if (o.clientValidation !== false){ // client validation failed
5666 this.failureType = Roo.form.Action.CLIENT_INVALID;
5667 this.form.afterAction(this, false);
5671 success : function(response)
5673 this.uploadComplete= true;
5674 if (this.haveProgress) {
5675 Roo.MessageBox.hide();
5679 var result = this.processResponse(response);
5680 if(result === true || result.success){
5681 this.form.afterAction(this, true);
5685 this.form.markInvalid(result.errors);
5686 this.failureType = Roo.form.Action.SERVER_INVALID;
5688 this.form.afterAction(this, false);
5690 failure : function(response)
5692 this.uploadComplete= true;
5693 if (this.haveProgress) {
5694 Roo.MessageBox.hide();
5697 this.response = response;
5698 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5699 this.form.afterAction(this, false);
5702 handleResponse : function(response){
5703 if(this.form.errorReader){
5704 var rs = this.form.errorReader.read(response);
5707 for(var i = 0, len = rs.records.length; i < len; i++) {
5708 var r = rs.records[i];
5712 if(errors.length < 1){
5716 success : rs.success,
5722 ret = Roo.decode(response.responseText);
5726 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
5736 Roo.form.Action.Load = function(form, options){
5737 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
5738 this.reader = this.form.reader;
5741 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
5746 Roo.Ajax.request(Roo.apply(
5747 this.createCallback(), {
5748 method:this.getMethod(),
5749 url:this.getUrl(false),
5750 params:this.getParams()
5754 success : function(response){
5756 var result = this.processResponse(response);
5757 if(result === true || !result.success || !result.data){
5758 this.failureType = Roo.form.Action.LOAD_FAILURE;
5759 this.form.afterAction(this, false);
5762 this.form.clearInvalid();
5763 this.form.setValues(result.data);
5764 this.form.afterAction(this, true);
5767 handleResponse : function(response){
5768 if(this.form.reader){
5769 var rs = this.form.reader.read(response);
5770 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
5772 success : rs.success,
5776 return Roo.decode(response.responseText);
5780 Roo.form.Action.ACTION_TYPES = {
5781 'load' : Roo.form.Action.Load,
5782 'submit' : Roo.form.Action.Submit
5791 * @class Roo.bootstrap.Form
5792 * @extends Roo.bootstrap.Component
5793 * Bootstrap Form class
5794 * @cfg {String} method GET | POST (default POST)
5795 * @cfg {String} labelAlign top | left (default top)
5796 * @cfg {String} align left | right - for navbars
5801 * @param {Object} config The config object
5805 Roo.bootstrap.Form = function(config){
5806 Roo.bootstrap.Form.superclass.constructor.call(this, config);
5809 * @event clientvalidation
5810 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
5811 * @param {Form} this
5812 * @param {Boolean} valid true if the form has passed client-side validation
5814 clientvalidation: true,
5816 * @event beforeaction
5817 * Fires before any action is performed. Return false to cancel the action.
5818 * @param {Form} this
5819 * @param {Action} action The action to be performed
5823 * @event actionfailed
5824 * Fires when an action fails.
5825 * @param {Form} this
5826 * @param {Action} action The action that failed
5828 actionfailed : true,
5830 * @event actioncomplete
5831 * Fires when an action is completed.
5832 * @param {Form} this
5833 * @param {Action} action The action that completed
5835 actioncomplete : true
5840 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
5843 * @cfg {String} method
5844 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
5849 * The URL to use for form actions if one isn't supplied in the action options.
5852 * @cfg {Boolean} fileUpload
5853 * Set to true if this form is a file upload.
5857 * @cfg {Object} baseParams
5858 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
5862 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
5866 * @cfg {Sting} align (left|right) for navbar forms
5871 activeAction : null,
5874 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5875 * element by passing it or its id or mask the form itself by passing in true.
5878 waitMsgTarget : false,
5883 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5884 * element by passing it or its id or mask the form itself by passing in true.
5888 getAutoCreate : function(){
5892 method : this.method || 'POST',
5893 id : this.id || Roo.id(),
5896 if (this.parent().xtype.match(/^Nav/)) {
5897 cfg.cls = 'navbar-form navbar-' + this.align;
5901 if (this.labelAlign == 'left' ) {
5902 cfg.cls += ' form-horizontal';
5908 initEvents : function()
5910 this.el.on('submit', this.onSubmit, this);
5911 // this was added as random key presses on the form where triggering form submit.
5912 this.el.on('keypress', function(e) {
5913 if (e.getCharCode() != 13) {
5916 // we might need to allow it for textareas.. and some other items.
5917 // check e.getTarget().
5919 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
5923 Roo.log("keypress blocked");
5931 onSubmit : function(e){
5936 * Returns true if client-side validation on the form is successful.
5939 isValid : function(){
5940 var items = this.getItems();
5942 items.each(function(f){
5951 * Returns true if any fields in this form have changed since their original load.
5954 isDirty : function(){
5956 var items = this.getItems();
5957 items.each(function(f){
5967 * Performs a predefined action (submit or load) or custom actions you define on this form.
5968 * @param {String} actionName The name of the action type
5969 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
5970 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
5971 * accept other config options):
5973 Property Type Description
5974 ---------------- --------------- ----------------------------------------------------------------------------------
5975 url String The url for the action (defaults to the form's url)
5976 method String The form method to use (defaults to the form's method, or POST if not defined)
5977 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
5978 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
5979 validate the form on the client (defaults to false)
5981 * @return {BasicForm} this
5983 doAction : function(action, options){
5984 if(typeof action == 'string'){
5985 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
5987 if(this.fireEvent('beforeaction', this, action) !== false){
5988 this.beforeAction(action);
5989 action.run.defer(100, action);
5995 beforeAction : function(action){
5996 var o = action.options;
5998 // not really supported yet.. ??
6000 //if(this.waitMsgTarget === true){
6001 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6002 //}else if(this.waitMsgTarget){
6003 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6004 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6006 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6012 afterAction : function(action, success){
6013 this.activeAction = null;
6014 var o = action.options;
6016 //if(this.waitMsgTarget === true){
6018 //}else if(this.waitMsgTarget){
6019 // this.waitMsgTarget.unmask();
6021 // Roo.MessageBox.updateProgress(1);
6022 // Roo.MessageBox.hide();
6029 Roo.callback(o.success, o.scope, [this, action]);
6030 this.fireEvent('actioncomplete', this, action);
6034 // failure condition..
6035 // we have a scenario where updates need confirming.
6036 // eg. if a locking scenario exists..
6037 // we look for { errors : { needs_confirm : true }} in the response.
6039 (typeof(action.result) != 'undefined') &&
6040 (typeof(action.result.errors) != 'undefined') &&
6041 (typeof(action.result.errors.needs_confirm) != 'undefined')
6044 Roo.log("not supported yet");
6047 Roo.MessageBox.confirm(
6048 "Change requires confirmation",
6049 action.result.errorMsg,
6054 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6064 Roo.callback(o.failure, o.scope, [this, action]);
6065 // show an error message if no failed handler is set..
6066 if (!this.hasListener('actionfailed')) {
6067 Roo.log("need to add dialog support");
6069 Roo.MessageBox.alert("Error",
6070 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6071 action.result.errorMsg :
6072 "Saving Failed, please check your entries or try again"
6077 this.fireEvent('actionfailed', this, action);
6082 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6083 * @param {String} id The value to search for
6086 findField : function(id){
6087 var items = this.getItems();
6088 var field = items.get(id);
6090 items.each(function(f){
6091 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6098 return field || null;
6101 * Mark fields in this form invalid in bulk.
6102 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6103 * @return {BasicForm} this
6105 markInvalid : function(errors){
6106 if(errors instanceof Array){
6107 for(var i = 0, len = errors.length; i < len; i++){
6108 var fieldError = errors[i];
6109 var f = this.findField(fieldError.id);
6111 f.markInvalid(fieldError.msg);
6117 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6118 field.markInvalid(errors[id]);
6122 //Roo.each(this.childForms || [], function (f) {
6123 // f.markInvalid(errors);
6130 * Set values for fields in this form in bulk.
6131 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6132 * @return {BasicForm} this
6134 setValues : function(values){
6135 if(values instanceof Array){ // array of objects
6136 for(var i = 0, len = values.length; i < len; i++){
6138 var f = this.findField(v.id);
6140 f.setValue(v.value);
6141 if(this.trackResetOnLoad){
6142 f.originalValue = f.getValue();
6146 }else{ // object hash
6149 if(typeof values[id] != 'function' && (field = this.findField(id))){
6151 if (field.setFromData &&
6153 field.displayField &&
6154 // combos' with local stores can
6155 // be queried via setValue()
6156 // to set their value..
6157 (field.store && !field.store.isLocal)
6161 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6162 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6163 field.setFromData(sd);
6166 field.setValue(values[id]);
6170 if(this.trackResetOnLoad){
6171 field.originalValue = field.getValue();
6177 //Roo.each(this.childForms || [], function (f) {
6178 // f.setValues(values);
6185 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6186 * they are returned as an array.
6187 * @param {Boolean} asString
6190 getValues : function(asString){
6191 //if (this.childForms) {
6192 // copy values from the child forms
6193 // Roo.each(this.childForms, function (f) {
6194 // this.setValues(f.getValues());
6200 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6201 if(asString === true){
6204 return Roo.urlDecode(fs);
6208 * Returns the fields in this form as an object with key/value pairs.
6209 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6212 getFieldValues : function(with_hidden)
6214 var items = this.getItems();
6216 items.each(function(f){
6220 var v = f.getValue();
6221 if (f.inputType =='radio') {
6222 if (typeof(ret[f.getName()]) == 'undefined') {
6223 ret[f.getName()] = ''; // empty..
6226 if (!f.el.dom.checked) {
6234 // not sure if this supported any more..
6235 if ((typeof(v) == 'object') && f.getRawValue) {
6236 v = f.getRawValue() ; // dates..
6238 // combo boxes where name != hiddenName...
6239 if (f.name != f.getName()) {
6240 ret[f.name] = f.getRawValue();
6242 ret[f.getName()] = v;
6249 * Clears all invalid messages in this form.
6250 * @return {BasicForm} this
6252 clearInvalid : function(){
6253 var items = this.getItems();
6255 items.each(function(f){
6266 * @return {BasicForm} this
6269 var items = this.getItems();
6270 items.each(function(f){
6274 Roo.each(this.childForms || [], function (f) {
6281 getItems : function()
6283 var r=new Roo.util.MixedCollection(false, function(o){
6284 return o.id || (o.id = Roo.id());
6286 var iter = function(el) {
6293 Roo.each(el.items,function(e) {
6312 * Ext JS Library 1.1.1
6313 * Copyright(c) 2006-2007, Ext JS, LLC.
6315 * Originally Released Under LGPL - original licence link has changed is not relivant.
6318 * <script type="text/javascript">
6321 * @class Roo.form.VTypes
6322 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6325 Roo.form.VTypes = function(){
6326 // closure these in so they are only created once.
6327 var alpha = /^[a-zA-Z_]+$/;
6328 var alphanum = /^[a-zA-Z0-9_]+$/;
6329 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6330 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6332 // All these messages and functions are configurable
6335 * The function used to validate email addresses
6336 * @param {String} value The email address
6338 'email' : function(v){
6339 return email.test(v);
6342 * The error text to display when the email validation function returns false
6345 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6347 * The keystroke filter mask to be applied on email input
6350 'emailMask' : /[a-z0-9_\.\-@]/i,
6353 * The function used to validate URLs
6354 * @param {String} value The URL
6356 'url' : function(v){
6360 * The error text to display when the url validation function returns false
6363 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6366 * The function used to validate alpha values
6367 * @param {String} value The value
6369 'alpha' : function(v){
6370 return alpha.test(v);
6373 * The error text to display when the alpha validation function returns false
6376 'alphaText' : 'This field should only contain letters and _',
6378 * The keystroke filter mask to be applied on alpha input
6381 'alphaMask' : /[a-z_]/i,
6384 * The function used to validate alphanumeric values
6385 * @param {String} value The value
6387 'alphanum' : function(v){
6388 return alphanum.test(v);
6391 * The error text to display when the alphanumeric validation function returns false
6394 'alphanumText' : 'This field should only contain letters, numbers and _',
6396 * The keystroke filter mask to be applied on alphanumeric input
6399 'alphanumMask' : /[a-z0-9_]/i
6409 * @class Roo.bootstrap.Input
6410 * @extends Roo.bootstrap.Component
6411 * Bootstrap Input class
6412 * @cfg {Boolean} disabled is it disabled
6413 * @cfg {String} fieldLabel - the label associated
6414 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6415 * @cfg {String} name name of the input
6416 * @cfg {string} fieldLabel - the label associated
6417 * @cfg {string} inputType - input / file submit ...
6418 * @cfg {string} placeholder - placeholder to put in text.
6419 * @cfg {string} before - input group add on before
6420 * @cfg {string} after - input group add on after
6421 * @cfg {string} size - (lg|sm) or leave empty..
6422 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6423 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6424 * @cfg {Number} md colspan out of 12 for computer-sized screens
6425 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6426 * @cfg {string} value default value of the input
6427 * @cfg {Number} labelWidth set the width of label (0-12)
6428 * @cfg {String} labelAlign (top|left)
6429 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6430 * @cfg {String} align (left|center|right) Default left
6434 * Create a new Input
6435 * @param {Object} config The config object
6438 Roo.bootstrap.Input = function(config){
6439 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6444 * Fires when this field receives input focus.
6445 * @param {Roo.form.Field} this
6450 * Fires when this field loses input focus.
6451 * @param {Roo.form.Field} this
6456 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6457 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6458 * @param {Roo.form.Field} this
6459 * @param {Roo.EventObject} e The event object
6464 * Fires just before the field blurs if the field value has changed.
6465 * @param {Roo.form.Field} this
6466 * @param {Mixed} newValue The new value
6467 * @param {Mixed} oldValue The original value
6472 * Fires after the field has been marked as invalid.
6473 * @param {Roo.form.Field} this
6474 * @param {String} msg The validation message
6479 * Fires after the field has been validated with no errors.
6480 * @param {Roo.form.Field} this
6485 * Fires after the key up
6486 * @param {Roo.form.Field} this
6487 * @param {Roo.EventObject} e The event Object
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 "")
6605 parentLabelAlign : function()
6608 while (parent.parent()) {
6609 parent = parent.parent();
6610 if (typeof(parent.labelAlign) !='undefined') {
6611 return parent.labelAlign;
6618 getAutoCreate : function(){
6620 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6626 if(this.inputType != 'hidden'){
6627 cfg.cls = 'form-group' //input-group
6633 type : this.inputType,
6635 cls : 'form-control',
6636 placeholder : this.placeholder || ''
6641 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
6644 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6645 input.maxLength = this.maxLength;
6648 if (this.disabled) {
6649 input.disabled=true;
6652 if (this.readOnly) {
6653 input.readonly=true;
6657 input.name = this.name;
6660 input.cls += ' input-' + this.size;
6663 ['xs','sm','md','lg'].map(function(size){
6664 if (settings[size]) {
6665 cfg.cls += ' col-' + size + '-' + settings[size];
6669 var inputblock = input;
6671 if (this.before || this.after) {
6674 cls : 'input-group',
6677 if (this.before && typeof(this.before) == 'string') {
6679 inputblock.cn.push({
6681 cls : 'roo-input-before input-group-addon',
6685 if (this.before && typeof(this.before) == 'object') {
6686 this.before = Roo.factory(this.before);
6687 Roo.log(this.before);
6688 inputblock.cn.push({
6690 cls : 'roo-input-before input-group-' +
6691 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6695 inputblock.cn.push(input);
6697 if (this.after && typeof(this.after) == 'string') {
6698 inputblock.cn.push({
6700 cls : 'roo-input-after input-group-addon',
6704 if (this.after && typeof(this.after) == 'object') {
6705 this.after = Roo.factory(this.after);
6706 Roo.log(this.after);
6707 inputblock.cn.push({
6709 cls : 'roo-input-after input-group-' +
6710 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6715 if (align ==='left' && this.fieldLabel.length) {
6716 Roo.log("left and has label");
6722 cls : 'control-label col-sm-' + this.labelWidth,
6723 html : this.fieldLabel
6727 cls : "col-sm-" + (12 - this.labelWidth),
6734 } else if ( this.fieldLabel.length) {
6740 //cls : 'input-group-addon',
6741 html : this.fieldLabel
6751 Roo.log(" no label && no align");
6760 Roo.log('input-parentType: ' + this.parentType);
6762 if (this.parentType === 'Navbar' && this.parent().bar) {
6763 cfg.cls += ' navbar-form';
6771 * return the real input element.
6773 inputEl: function ()
6775 return this.el.select('input.form-control',true).first();
6777 setDisabled : function(v)
6779 var i = this.inputEl().dom;
6781 i.removeAttribute('disabled');
6785 i.setAttribute('disabled','true');
6787 initEvents : function()
6790 this.inputEl().on("keydown" , this.fireKey, this);
6791 this.inputEl().on("focus", this.onFocus, this);
6792 this.inputEl().on("blur", this.onBlur, this);
6794 this.inputEl().relayEvent('keyup', this);
6796 // reference to original value for reset
6797 this.originalValue = this.getValue();
6798 //Roo.form.TextField.superclass.initEvents.call(this);
6799 if(this.validationEvent == 'keyup'){
6800 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
6801 this.inputEl().on('keyup', this.filterValidation, this);
6803 else if(this.validationEvent !== false){
6804 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
6807 if(this.selectOnFocus){
6808 this.on("focus", this.preFocus, this);
6811 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
6812 this.inputEl().on("keypress", this.filterKeys, this);
6815 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
6816 this.el.on("click", this.autoSize, this);
6819 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
6820 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
6823 if (typeof(this.before) == 'object') {
6824 this.before.render(this.el.select('.roo-input-before',true).first());
6826 if (typeof(this.after) == 'object') {
6827 this.after.render(this.el.select('.roo-input-after',true).first());
6832 filterValidation : function(e){
6833 if(!e.isNavKeyPress()){
6834 this.validationTask.delay(this.validationDelay);
6838 * Validates the field value
6839 * @return {Boolean} True if the value is valid, else false
6841 validate : function(){
6842 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
6843 if(this.disabled || this.validateValue(this.getRawValue())){
6844 this.clearInvalid();
6852 * Validates a value according to the field's validation rules and marks the field as invalid
6853 * if the validation fails
6854 * @param {Mixed} value The value to validate
6855 * @return {Boolean} True if the value is valid, else false
6857 validateValue : function(value){
6858 if(value.length < 1) { // if it's blank
6859 if(this.allowBlank){
6860 this.clearInvalid();
6863 this.markInvalid(this.blankText);
6867 if(value.length < this.minLength){
6868 this.markInvalid(String.format(this.minLengthText, this.minLength));
6871 if(value.length > this.maxLength){
6872 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
6876 var vt = Roo.form.VTypes;
6877 if(!vt[this.vtype](value, this)){
6878 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
6882 if(typeof this.validator == "function"){
6883 var msg = this.validator(value);
6885 this.markInvalid(msg);
6889 if(this.regex && !this.regex.test(value)){
6890 this.markInvalid(this.regexText);
6899 fireKey : function(e){
6900 //Roo.log('field ' + e.getKey());
6901 if(e.isNavKeyPress()){
6902 this.fireEvent("specialkey", this, e);
6905 focus : function (selectText){
6907 this.inputEl().focus();
6908 if(selectText === true){
6909 this.inputEl().dom.select();
6915 onFocus : function(){
6916 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6917 // this.el.addClass(this.focusClass);
6920 this.hasFocus = true;
6921 this.startValue = this.getValue();
6922 this.fireEvent("focus", this);
6926 beforeBlur : Roo.emptyFn,
6930 onBlur : function(){
6932 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6933 //this.el.removeClass(this.focusClass);
6935 this.hasFocus = false;
6936 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
6939 var v = this.getValue();
6940 if(String(v) !== String(this.startValue)){
6941 this.fireEvent('change', this, v, this.startValue);
6943 this.fireEvent("blur", this);
6947 * Resets the current field value to the originally loaded value and clears any validation messages
6950 this.setValue(this.originalValue);
6951 this.clearInvalid();
6954 * Returns the name of the field
6955 * @return {Mixed} name The name field
6957 getName: function(){
6961 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
6962 * @return {Mixed} value The field value
6964 getValue : function(){
6965 return this.inputEl().getValue();
6968 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
6969 * @return {Mixed} value The field value
6971 getRawValue : function(){
6972 var v = this.inputEl().getValue();
6978 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
6979 * @param {Mixed} value The value to set
6981 setRawValue : function(v){
6982 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6985 selectText : function(start, end){
6986 var v = this.getRawValue();
6988 start = start === undefined ? 0 : start;
6989 end = end === undefined ? v.length : end;
6990 var d = this.inputEl().dom;
6991 if(d.setSelectionRange){
6992 d.setSelectionRange(start, end);
6993 }else if(d.createTextRange){
6994 var range = d.createTextRange();
6995 range.moveStart("character", start);
6996 range.moveEnd("character", v.length-end);
7003 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7004 * @param {Mixed} value The value to set
7006 setValue : function(v){
7009 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7015 processValue : function(value){
7016 if(this.stripCharsRe){
7017 var newValue = value.replace(this.stripCharsRe, '');
7018 if(newValue !== value){
7019 this.setRawValue(newValue);
7026 preFocus : function(){
7028 if(this.selectOnFocus){
7029 this.inputEl().dom.select();
7032 filterKeys : function(e){
7034 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7037 var c = e.getCharCode(), cc = String.fromCharCode(c);
7038 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7041 if(!this.maskRe.test(cc)){
7046 * Clear any invalid styles/messages for this field
7048 clearInvalid : function(){
7050 if(!this.el || this.preventMark){ // not rendered
7053 this.el.removeClass(this.invalidClass);
7055 switch(this.msgTarget){
7057 this.el.dom.qtip = '';
7060 this.el.dom.title = '';
7064 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7069 this.errorIcon.dom.qtip = '';
7070 this.errorIcon.hide();
7071 this.un('resize', this.alignErrorIcon, this);
7075 var t = Roo.getDom(this.msgTarget);
7077 t.style.display = 'none';
7081 this.fireEvent('valid', this);
7084 * Mark this field as invalid
7085 * @param {String} msg The validation message
7087 markInvalid : function(msg){
7088 if(!this.el || this.preventMark){ // not rendered
7091 this.el.addClass(this.invalidClass);
7093 msg = msg || this.invalidText;
7094 switch(this.msgTarget){
7096 this.el.dom.qtip = msg;
7097 this.el.dom.qclass = 'x-form-invalid-tip';
7098 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7099 Roo.QuickTips.enable();
7103 this.el.dom.title = msg;
7107 var elp = this.el.findParent('.x-form-element', 5, true);
7108 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7109 this.errorEl.setWidth(elp.getWidth(true)-20);
7111 this.errorEl.update(msg);
7112 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7115 if(!this.errorIcon){
7116 var elp = this.el.findParent('.x-form-element', 5, true);
7117 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7119 this.alignErrorIcon();
7120 this.errorIcon.dom.qtip = msg;
7121 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7122 this.errorIcon.show();
7123 this.on('resize', this.alignErrorIcon, this);
7126 var t = Roo.getDom(this.msgTarget);
7128 t.style.display = this.msgDisplay;
7132 this.fireEvent('invalid', this, msg);
7135 SafariOnKeyDown : function(event)
7137 // this is a workaround for a password hang bug on chrome/ webkit.
7139 var isSelectAll = false;
7141 if(this.inputEl().dom.selectionEnd > 0){
7142 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7144 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7145 event.preventDefault();
7150 if(isSelectAll){ // backspace and delete key
7152 event.preventDefault();
7153 // this is very hacky as keydown always get's upper case.
7155 var cc = String.fromCharCode(event.getCharCode());
7156 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7160 adjustWidth : function(tag, w){
7161 tag = tag.toLowerCase();
7162 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7163 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7167 if(tag == 'textarea'){
7170 }else if(Roo.isOpera){
7174 if(tag == 'textarea'){
7193 * @class Roo.bootstrap.TextArea
7194 * @extends Roo.bootstrap.Input
7195 * Bootstrap TextArea class
7196 * @cfg {Number} cols Specifies the visible width of a text area
7197 * @cfg {Number} rows Specifies the visible number of lines in a text area
7198 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7199 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7200 * @cfg {string} html text
7203 * Create a new TextArea
7204 * @param {Object} config The config object
7207 Roo.bootstrap.TextArea = function(config){
7208 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7212 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7222 getAutoCreate : function(){
7224 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7235 value : this.value || '',
7236 html: this.html || '',
7237 cls : 'form-control',
7238 placeholder : this.placeholder || ''
7242 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7243 input.maxLength = this.maxLength;
7247 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7251 input.cols = this.cols;
7254 if (this.readOnly) {
7255 input.readonly = true;
7259 input.name = this.name;
7263 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7267 ['xs','sm','md','lg'].map(function(size){
7268 if (settings[size]) {
7269 cfg.cls += ' col-' + size + '-' + settings[size];
7273 var inputblock = input;
7275 if (this.before || this.after) {
7278 cls : 'input-group',
7282 inputblock.cn.push({
7284 cls : 'input-group-addon',
7288 inputblock.cn.push(input);
7290 inputblock.cn.push({
7292 cls : 'input-group-addon',
7299 if (align ==='left' && this.fieldLabel.length) {
7300 Roo.log("left and has label");
7306 cls : 'control-label col-sm-' + this.labelWidth,
7307 html : this.fieldLabel
7311 cls : "col-sm-" + (12 - this.labelWidth),
7318 } else if ( this.fieldLabel.length) {
7324 //cls : 'input-group-addon',
7325 html : this.fieldLabel
7335 Roo.log(" no label && no align");
7345 if (this.disabled) {
7346 input.disabled=true;
7353 * return the real textarea element.
7355 inputEl: function ()
7357 return this.el.select('textarea.form-control',true).first();
7365 * trigger field - base class for combo..
7370 * @class Roo.bootstrap.TriggerField
7371 * @extends Roo.bootstrap.Input
7372 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7373 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7374 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7375 * for which you can provide a custom implementation. For example:
7377 var trigger = new Roo.bootstrap.TriggerField();
7378 trigger.onTriggerClick = myTriggerFn;
7379 trigger.applyTo('my-field');
7382 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7383 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7384 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7385 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7387 * Create a new TriggerField.
7388 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7389 * to the base TextField)
7391 Roo.bootstrap.TriggerField = function(config){
7392 this.mimicing = false;
7393 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7396 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7398 * @cfg {String} triggerClass A CSS class to apply to the trigger
7401 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7405 /** @cfg {Boolean} grow @hide */
7406 /** @cfg {Number} growMin @hide */
7407 /** @cfg {Number} growMax @hide */
7413 autoSize: Roo.emptyFn,
7420 actionMode : 'wrap',
7424 getAutoCreate : function(){
7426 var parent = this.parent();
7428 var align = this.labelAlign || this.parentLabelAlign();
7433 cls: 'form-group' //input-group
7440 type : this.inputType,
7441 cls : 'form-control',
7442 autocomplete: 'off',
7443 placeholder : this.placeholder || ''
7447 input.name = this.name;
7450 input.cls += ' input-' + this.size;
7453 if (this.disabled) {
7454 input.disabled=true;
7457 var inputblock = input;
7459 if (this.before || this.after) {
7462 cls : 'input-group',
7466 inputblock.cn.push({
7468 cls : 'input-group-addon',
7472 inputblock.cn.push(input);
7474 inputblock.cn.push({
7476 cls : 'input-group-addon',
7489 cls: 'form-hidden-field'
7497 Roo.log('multiple');
7505 cls: 'form-hidden-field'
7509 cls: 'select2-choices',
7513 cls: 'select2-search-field',
7526 cls: 'select2-container input-group',
7531 cls: 'typeahead typeahead-long dropdown-menu',
7532 style: 'display:none'
7540 cls : 'input-group-addon btn dropdown-toggle',
7548 cls: 'combobox-clear',
7562 combobox.cls += ' select2-container-multi';
7565 if (align ==='left' && this.fieldLabel.length) {
7567 Roo.log("left and has label");
7573 cls : 'control-label col-sm-' + this.labelWidth,
7574 html : this.fieldLabel
7578 cls : "col-sm-" + (12 - this.labelWidth),
7585 } else if ( this.fieldLabel.length) {
7591 //cls : 'input-group-addon',
7592 html : this.fieldLabel
7602 Roo.log(" no label && no align");
7609 ['xs','sm','md','lg'].map(function(size){
7610 if (settings[size]) {
7611 cfg.cls += ' col-' + size + '-' + settings[size];
7622 onResize : function(w, h){
7623 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
7624 // if(typeof w == 'number'){
7625 // var x = w - this.trigger.getWidth();
7626 // this.inputEl().setWidth(this.adjustWidth('input', x));
7627 // this.trigger.setStyle('left', x+'px');
7632 adjustSize : Roo.BoxComponent.prototype.adjustSize,
7635 getResizeEl : function(){
7636 return this.inputEl();
7640 getPositionEl : function(){
7641 return this.inputEl();
7645 alignErrorIcon : function(){
7646 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
7650 initEvents : function(){
7652 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
7653 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
7655 this.trigger = this.el.select('span.dropdown-toggle',true).first();
7656 if(this.hideTrigger){
7657 this.trigger.setDisplayed(false);
7659 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
7663 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
7666 //this.trigger.addClassOnOver('x-form-trigger-over');
7667 //this.trigger.addClassOnClick('x-form-trigger-click');
7670 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
7675 initTrigger : function(){
7680 onDestroy : function(){
7682 this.trigger.removeAllListeners();
7683 // this.trigger.remove();
7686 // this.wrap.remove();
7688 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
7692 onFocus : function(){
7693 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
7696 this.wrap.addClass('x-trigger-wrap-focus');
7697 this.mimicing = true;
7698 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
7699 if(this.monitorTab){
7700 this.el.on("keydown", this.checkTab, this);
7707 checkTab : function(e){
7708 if(e.getKey() == e.TAB){
7714 onBlur : function(){
7719 mimicBlur : function(e, t){
7721 if(!this.wrap.contains(t) && this.validateBlur()){
7728 triggerBlur : function(){
7729 this.mimicing = false;
7730 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
7731 if(this.monitorTab){
7732 this.el.un("keydown", this.checkTab, this);
7734 //this.wrap.removeClass('x-trigger-wrap-focus');
7735 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
7739 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
7740 validateBlur : function(e, t){
7745 onDisable : function(){
7746 this.inputEl().dom.disabled = true;
7747 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
7749 // this.wrap.addClass('x-item-disabled');
7754 onEnable : function(){
7755 this.inputEl().dom.disabled = false;
7756 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
7758 // this.el.removeClass('x-item-disabled');
7763 onShow : function(){
7764 var ae = this.getActionEl();
7767 ae.dom.style.display = '';
7768 ae.dom.style.visibility = 'visible';
7774 onHide : function(){
7775 var ae = this.getActionEl();
7776 ae.dom.style.display = 'none';
7780 * The function that should handle the trigger's click event. This method does nothing by default until overridden
7781 * by an implementing function.
7783 * @param {EventObject} e
7785 onTriggerClick : Roo.emptyFn
7789 * Ext JS Library 1.1.1
7790 * Copyright(c) 2006-2007, Ext JS, LLC.
7792 * Originally Released Under LGPL - original licence link has changed is not relivant.
7795 * <script type="text/javascript">
7800 * @class Roo.data.SortTypes
7802 * Defines the default sorting (casting?) comparison functions used when sorting data.
7804 Roo.data.SortTypes = {
7806 * Default sort that does nothing
7807 * @param {Mixed} s The value being converted
7808 * @return {Mixed} The comparison value
7815 * The regular expression used to strip tags
7819 stripTagsRE : /<\/?[^>]+>/gi,
7822 * Strips all HTML tags to sort on text only
7823 * @param {Mixed} s The value being converted
7824 * @return {String} The comparison value
7826 asText : function(s){
7827 return String(s).replace(this.stripTagsRE, "");
7831 * Strips all HTML tags to sort on text only - Case insensitive
7832 * @param {Mixed} s The value being converted
7833 * @return {String} The comparison value
7835 asUCText : function(s){
7836 return String(s).toUpperCase().replace(this.stripTagsRE, "");
7840 * Case insensitive string
7841 * @param {Mixed} s The value being converted
7842 * @return {String} The comparison value
7844 asUCString : function(s) {
7845 return String(s).toUpperCase();
7850 * @param {Mixed} s The value being converted
7851 * @return {Number} The comparison value
7853 asDate : function(s) {
7857 if(s instanceof Date){
7860 return Date.parse(String(s));
7865 * @param {Mixed} s The value being converted
7866 * @return {Float} The comparison value
7868 asFloat : function(s) {
7869 var val = parseFloat(String(s).replace(/,/g, ""));
7870 if(isNaN(val)) val = 0;
7876 * @param {Mixed} s The value being converted
7877 * @return {Number} The comparison value
7879 asInt : function(s) {
7880 var val = parseInt(String(s).replace(/,/g, ""));
7881 if(isNaN(val)) val = 0;
7886 * Ext JS Library 1.1.1
7887 * Copyright(c) 2006-2007, Ext JS, LLC.
7889 * Originally Released Under LGPL - original licence link has changed is not relivant.
7892 * <script type="text/javascript">
7896 * @class Roo.data.Record
7897 * Instances of this class encapsulate both record <em>definition</em> information, and record
7898 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
7899 * to access Records cached in an {@link Roo.data.Store} object.<br>
7901 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
7902 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
7905 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
7907 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
7908 * {@link #create}. The parameters are the same.
7909 * @param {Array} data An associative Array of data values keyed by the field name.
7910 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
7911 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
7912 * not specified an integer id is generated.
7914 Roo.data.Record = function(data, id){
7915 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
7920 * Generate a constructor for a specific record layout.
7921 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
7922 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
7923 * Each field definition object may contain the following properties: <ul>
7924 * <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,
7925 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
7926 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
7927 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
7928 * is being used, then this is a string containing the javascript expression to reference the data relative to
7929 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
7930 * to the data item relative to the record element. If the mapping expression is the same as the field name,
7931 * this may be omitted.</p></li>
7932 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
7933 * <ul><li>auto (Default, implies no conversion)</li>
7938 * <li>date</li></ul></p></li>
7939 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
7940 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
7941 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
7942 * by the Reader into an object that will be stored in the Record. It is passed the
7943 * following parameters:<ul>
7944 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
7946 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
7948 * <br>usage:<br><pre><code>
7949 var TopicRecord = Roo.data.Record.create(
7950 {name: 'title', mapping: 'topic_title'},
7951 {name: 'author', mapping: 'username'},
7952 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
7953 {name: 'lastPost', mapping: 'post_time', type: 'date'},
7954 {name: 'lastPoster', mapping: 'user2'},
7955 {name: 'excerpt', mapping: 'post_text'}
7958 var myNewRecord = new TopicRecord({
7959 title: 'Do my job please',
7962 lastPost: new Date(),
7963 lastPoster: 'Animal',
7964 excerpt: 'No way dude!'
7966 myStore.add(myNewRecord);
7971 Roo.data.Record.create = function(o){
7973 f.superclass.constructor.apply(this, arguments);
7975 Roo.extend(f, Roo.data.Record);
7976 var p = f.prototype;
7977 p.fields = new Roo.util.MixedCollection(false, function(field){
7980 for(var i = 0, len = o.length; i < len; i++){
7981 p.fields.add(new Roo.data.Field(o[i]));
7983 f.getField = function(name){
7984 return p.fields.get(name);
7989 Roo.data.Record.AUTO_ID = 1000;
7990 Roo.data.Record.EDIT = 'edit';
7991 Roo.data.Record.REJECT = 'reject';
7992 Roo.data.Record.COMMIT = 'commit';
7994 Roo.data.Record.prototype = {
7996 * Readonly flag - true if this record has been modified.
8005 join : function(store){
8010 * Set the named field to the specified value.
8011 * @param {String} name The name of the field to set.
8012 * @param {Object} value The value to set the field to.
8014 set : function(name, value){
8015 if(this.data[name] == value){
8022 if(typeof this.modified[name] == 'undefined'){
8023 this.modified[name] = this.data[name];
8025 this.data[name] = value;
8026 if(!this.editing && this.store){
8027 this.store.afterEdit(this);
8032 * Get the value of the named field.
8033 * @param {String} name The name of the field to get the value of.
8034 * @return {Object} The value of the field.
8036 get : function(name){
8037 return this.data[name];
8041 beginEdit : function(){
8042 this.editing = true;
8047 cancelEdit : function(){
8048 this.editing = false;
8049 delete this.modified;
8053 endEdit : function(){
8054 this.editing = false;
8055 if(this.dirty && this.store){
8056 this.store.afterEdit(this);
8061 * Usually called by the {@link Roo.data.Store} which owns the Record.
8062 * Rejects all changes made to the Record since either creation, or the last commit operation.
8063 * Modified fields are reverted to their original values.
8065 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8066 * of reject operations.
8068 reject : function(){
8069 var m = this.modified;
8071 if(typeof m[n] != "function"){
8072 this.data[n] = m[n];
8076 delete this.modified;
8077 this.editing = false;
8079 this.store.afterReject(this);
8084 * Usually called by the {@link Roo.data.Store} which owns the Record.
8085 * Commits all changes made to the Record since either creation, or the last commit operation.
8087 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8088 * of commit operations.
8090 commit : function(){
8092 delete this.modified;
8093 this.editing = false;
8095 this.store.afterCommit(this);
8100 hasError : function(){
8101 return this.error != null;
8105 clearError : function(){
8110 * Creates a copy of this record.
8111 * @param {String} id (optional) A new record id if you don't want to use this record's id
8114 copy : function(newId) {
8115 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8119 * Ext JS Library 1.1.1
8120 * Copyright(c) 2006-2007, Ext JS, LLC.
8122 * Originally Released Under LGPL - original licence link has changed is not relivant.
8125 * <script type="text/javascript">
8131 * @class Roo.data.Store
8132 * @extends Roo.util.Observable
8133 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8134 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8136 * 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
8137 * has no knowledge of the format of the data returned by the Proxy.<br>
8139 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8140 * instances from the data object. These records are cached and made available through accessor functions.
8142 * Creates a new Store.
8143 * @param {Object} config A config object containing the objects needed for the Store to access data,
8144 * and read the data into Records.
8146 Roo.data.Store = function(config){
8147 this.data = new Roo.util.MixedCollection(false);
8148 this.data.getKey = function(o){
8151 this.baseParams = {};
8158 "multisort" : "_multisort"
8161 if(config && config.data){
8162 this.inlineData = config.data;
8166 Roo.apply(this, config);
8168 if(this.reader){ // reader passed
8169 this.reader = Roo.factory(this.reader, Roo.data);
8170 this.reader.xmodule = this.xmodule || false;
8171 if(!this.recordType){
8172 this.recordType = this.reader.recordType;
8174 if(this.reader.onMetaChange){
8175 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8179 if(this.recordType){
8180 this.fields = this.recordType.prototype.fields;
8186 * @event datachanged
8187 * Fires when the data cache has changed, and a widget which is using this Store
8188 * as a Record cache should refresh its view.
8189 * @param {Store} this
8194 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8195 * @param {Store} this
8196 * @param {Object} meta The JSON metadata
8201 * Fires when Records have been added to the Store
8202 * @param {Store} this
8203 * @param {Roo.data.Record[]} records The array of Records added
8204 * @param {Number} index The index at which the record(s) were added
8209 * Fires when a Record has been removed from the Store
8210 * @param {Store} this
8211 * @param {Roo.data.Record} record The Record that was removed
8212 * @param {Number} index The index at which the record was removed
8217 * Fires when a Record has been updated
8218 * @param {Store} this
8219 * @param {Roo.data.Record} record The Record that was updated
8220 * @param {String} operation The update operation being performed. Value may be one of:
8222 Roo.data.Record.EDIT
8223 Roo.data.Record.REJECT
8224 Roo.data.Record.COMMIT
8230 * Fires when the data cache has been cleared.
8231 * @param {Store} this
8236 * Fires before a request is made for a new data object. If the beforeload handler returns false
8237 * the load action will be canceled.
8238 * @param {Store} this
8239 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8243 * @event beforeloadadd
8244 * Fires after a new set of Records has been loaded.
8245 * @param {Store} this
8246 * @param {Roo.data.Record[]} records The Records that were loaded
8247 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8249 beforeloadadd : true,
8252 * Fires after a new set of Records has been loaded, before they are added to the store.
8253 * @param {Store} this
8254 * @param {Roo.data.Record[]} records The Records that were loaded
8255 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8256 * @params {Object} return from reader
8260 * @event loadexception
8261 * Fires if an exception occurs in the Proxy during loading.
8262 * Called with the signature of the Proxy's "loadexception" event.
8263 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8266 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8267 * @param {Object} load options
8268 * @param {Object} jsonData from your request (normally this contains the Exception)
8270 loadexception : true
8274 this.proxy = Roo.factory(this.proxy, Roo.data);
8275 this.proxy.xmodule = this.xmodule || false;
8276 this.relayEvents(this.proxy, ["loadexception"]);
8278 this.sortToggle = {};
8279 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8281 Roo.data.Store.superclass.constructor.call(this);
8283 if(this.inlineData){
8284 this.loadData(this.inlineData);
8285 delete this.inlineData;
8289 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8291 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8292 * without a remote query - used by combo/forms at present.
8296 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8299 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8302 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8303 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8306 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8307 * on any HTTP request
8310 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8313 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8317 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8318 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8323 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8324 * loaded or when a record is removed. (defaults to false).
8326 pruneModifiedRecords : false,
8332 * Add Records to the Store and fires the add event.
8333 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8335 add : function(records){
8336 records = [].concat(records);
8337 for(var i = 0, len = records.length; i < len; i++){
8338 records[i].join(this);
8340 var index = this.data.length;
8341 this.data.addAll(records);
8342 this.fireEvent("add", this, records, index);
8346 * Remove a Record from the Store and fires the remove event.
8347 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8349 remove : function(record){
8350 var index = this.data.indexOf(record);
8351 this.data.removeAt(index);
8352 if(this.pruneModifiedRecords){
8353 this.modified.remove(record);
8355 this.fireEvent("remove", this, record, index);
8359 * Remove all Records from the Store and fires the clear event.
8361 removeAll : function(){
8363 if(this.pruneModifiedRecords){
8366 this.fireEvent("clear", this);
8370 * Inserts Records to the Store at the given index and fires the add event.
8371 * @param {Number} index The start index at which to insert the passed Records.
8372 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8374 insert : function(index, records){
8375 records = [].concat(records);
8376 for(var i = 0, len = records.length; i < len; i++){
8377 this.data.insert(index, records[i]);
8378 records[i].join(this);
8380 this.fireEvent("add", this, records, index);
8384 * Get the index within the cache of the passed Record.
8385 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8386 * @return {Number} The index of the passed Record. Returns -1 if not found.
8388 indexOf : function(record){
8389 return this.data.indexOf(record);
8393 * Get the index within the cache of the Record with the passed id.
8394 * @param {String} id The id of the Record to find.
8395 * @return {Number} The index of the Record. Returns -1 if not found.
8397 indexOfId : function(id){
8398 return this.data.indexOfKey(id);
8402 * Get the Record with the specified id.
8403 * @param {String} id The id of the Record to find.
8404 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8406 getById : function(id){
8407 return this.data.key(id);
8411 * Get the Record at the specified index.
8412 * @param {Number} index The index of the Record to find.
8413 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8415 getAt : function(index){
8416 return this.data.itemAt(index);
8420 * Returns a range of Records between specified indices.
8421 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8422 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8423 * @return {Roo.data.Record[]} An array of Records
8425 getRange : function(start, end){
8426 return this.data.getRange(start, end);
8430 storeOptions : function(o){
8431 o = Roo.apply({}, o);
8434 this.lastOptions = o;
8438 * Loads the Record cache from the configured Proxy using the configured Reader.
8440 * If using remote paging, then the first load call must specify the <em>start</em>
8441 * and <em>limit</em> properties in the options.params property to establish the initial
8442 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8444 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8445 * and this call will return before the new data has been loaded. Perform any post-processing
8446 * in a callback function, or in a "load" event handler.</strong>
8448 * @param {Object} options An object containing properties which control loading options:<ul>
8449 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8450 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8451 * passed the following arguments:<ul>
8452 * <li>r : Roo.data.Record[]</li>
8453 * <li>options: Options object from the load call</li>
8454 * <li>success: Boolean success indicator</li></ul></li>
8455 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8456 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8459 load : function(options){
8460 options = options || {};
8461 if(this.fireEvent("beforeload", this, options) !== false){
8462 this.storeOptions(options);
8463 var p = Roo.apply(options.params || {}, this.baseParams);
8464 // if meta was not loaded from remote source.. try requesting it.
8465 if (!this.reader.metaFromRemote) {
8468 if(this.sortInfo && this.remoteSort){
8469 var pn = this.paramNames;
8470 p[pn["sort"]] = this.sortInfo.field;
8471 p[pn["dir"]] = this.sortInfo.direction;
8473 if (this.multiSort) {
8474 var pn = this.paramNames;
8475 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8478 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8483 * Reloads the Record cache from the configured Proxy using the configured Reader and
8484 * the options from the last load operation performed.
8485 * @param {Object} options (optional) An object containing properties which may override the options
8486 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8487 * the most recently used options are reused).
8489 reload : function(options){
8490 this.load(Roo.applyIf(options||{}, this.lastOptions));
8494 // Called as a callback by the Reader during a load operation.
8495 loadRecords : function(o, options, success){
8496 if(!o || success === false){
8497 if(success !== false){
8498 this.fireEvent("load", this, [], options, o);
8500 if(options.callback){
8501 options.callback.call(options.scope || this, [], options, false);
8505 // if data returned failure - throw an exception.
8506 if (o.success === false) {
8507 // show a message if no listener is registered.
8508 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8509 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8511 // loadmask wil be hooked into this..
8512 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8515 var r = o.records, t = o.totalRecords || r.length;
8517 this.fireEvent("beforeloadadd", this, r, options, o);
8519 if(!options || options.add !== true){
8520 if(this.pruneModifiedRecords){
8523 for(var i = 0, len = r.length; i < len; i++){
8527 this.data = this.snapshot;
8528 delete this.snapshot;
8531 this.data.addAll(r);
8532 this.totalLength = t;
8534 this.fireEvent("datachanged", this);
8536 this.totalLength = Math.max(t, this.data.length+r.length);
8539 this.fireEvent("load", this, r, options, o);
8540 if(options.callback){
8541 options.callback.call(options.scope || this, r, options, true);
8547 * Loads data from a passed data block. A Reader which understands the format of the data
8548 * must have been configured in the constructor.
8549 * @param {Object} data The data block from which to read the Records. The format of the data expected
8550 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8551 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8553 loadData : function(o, append){
8554 var r = this.reader.readRecords(o);
8555 this.loadRecords(r, {add: append}, true);
8559 * Gets the number of cached records.
8561 * <em>If using paging, this may not be the total size of the dataset. If the data object
8562 * used by the Reader contains the dataset size, then the getTotalCount() function returns
8563 * the data set size</em>
8565 getCount : function(){
8566 return this.data.length || 0;
8570 * Gets the total number of records in the dataset as returned by the server.
8572 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8573 * the dataset size</em>
8575 getTotalCount : function(){
8576 return this.totalLength || 0;
8580 * Returns the sort state of the Store as an object with two properties:
8582 field {String} The name of the field by which the Records are sorted
8583 direction {String} The sort order, "ASC" or "DESC"
8586 getSortState : function(){
8587 return this.sortInfo;
8591 applySort : function(){
8592 if(this.sortInfo && !this.remoteSort){
8593 var s = this.sortInfo, f = s.field;
8594 var st = this.fields.get(f).sortType;
8595 var fn = function(r1, r2){
8596 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8597 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8599 this.data.sort(s.direction, fn);
8600 if(this.snapshot && this.snapshot != this.data){
8601 this.snapshot.sort(s.direction, fn);
8607 * Sets the default sort column and order to be used by the next load operation.
8608 * @param {String} fieldName The name of the field to sort by.
8609 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8611 setDefaultSort : function(field, dir){
8612 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
8617 * If remote sorting is used, the sort is performed on the server, and the cache is
8618 * reloaded. If local sorting is used, the cache is sorted internally.
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 sort : function(fieldName, dir){
8623 var f = this.fields.get(fieldName);
8625 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
8627 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
8628 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
8633 this.sortToggle[f.name] = dir;
8634 this.sortInfo = {field: f.name, direction: dir};
8635 if(!this.remoteSort){
8637 this.fireEvent("datachanged", this);
8639 this.load(this.lastOptions);
8644 * Calls the specified function for each of the Records in the cache.
8645 * @param {Function} fn The function to call. The Record is passed as the first parameter.
8646 * Returning <em>false</em> aborts and exits the iteration.
8647 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
8649 each : function(fn, scope){
8650 this.data.each(fn, scope);
8654 * Gets all records modified since the last commit. Modified records are persisted across load operations
8655 * (e.g., during paging).
8656 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
8658 getModifiedRecords : function(){
8659 return this.modified;
8663 createFilterFn : function(property, value, anyMatch){
8664 if(!value.exec){ // not a regex
8665 value = String(value);
8666 if(value.length == 0){
8669 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
8672 return value.test(r.data[property]);
8677 * Sums the value of <i>property</i> for each record between start and end and returns the result.
8678 * @param {String} property A field on your records
8679 * @param {Number} start The record index to start at (defaults to 0)
8680 * @param {Number} end The last record index to include (defaults to length - 1)
8681 * @return {Number} The sum
8683 sum : function(property, start, end){
8684 var rs = this.data.items, v = 0;
8686 end = (end || end === 0) ? end : rs.length-1;
8688 for(var i = start; i <= end; i++){
8689 v += (rs[i].data[property] || 0);
8695 * Filter the records by a specified property.
8696 * @param {String} field A field on your records
8697 * @param {String/RegExp} value Either a string that the field
8698 * should start with or a RegExp to test against the field
8699 * @param {Boolean} anyMatch True to match any part not just the beginning
8701 filter : function(property, value, anyMatch){
8702 var fn = this.createFilterFn(property, value, anyMatch);
8703 return fn ? this.filterBy(fn) : this.clearFilter();
8707 * Filter by a function. The specified function will be called with each
8708 * record in this data source. If the function returns true the record is included,
8709 * otherwise it is filtered.
8710 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8711 * @param {Object} scope (optional) The scope of the function (defaults to this)
8713 filterBy : function(fn, scope){
8714 this.snapshot = this.snapshot || this.data;
8715 this.data = this.queryBy(fn, scope||this);
8716 this.fireEvent("datachanged", this);
8720 * Query the records by a specified property.
8721 * @param {String} field A field on your records
8722 * @param {String/RegExp} value Either a string that the field
8723 * should start with or a RegExp to test against the field
8724 * @param {Boolean} anyMatch True to match any part not just the beginning
8725 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8727 query : function(property, value, anyMatch){
8728 var fn = this.createFilterFn(property, value, anyMatch);
8729 return fn ? this.queryBy(fn) : this.data.clone();
8733 * Query by a function. The specified function will be called with each
8734 * record in this data source. If the function returns true the record is included
8736 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8737 * @param {Object} scope (optional) The scope of the function (defaults to this)
8738 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8740 queryBy : function(fn, scope){
8741 var data = this.snapshot || this.data;
8742 return data.filterBy(fn, scope||this);
8746 * Collects unique values for a particular dataIndex from this store.
8747 * @param {String} dataIndex The property to collect
8748 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
8749 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
8750 * @return {Array} An array of the unique values
8752 collect : function(dataIndex, allowNull, bypassFilter){
8753 var d = (bypassFilter === true && this.snapshot) ?
8754 this.snapshot.items : this.data.items;
8755 var v, sv, r = [], l = {};
8756 for(var i = 0, len = d.length; i < len; i++){
8757 v = d[i].data[dataIndex];
8759 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
8768 * Revert to a view of the Record cache with no filtering applied.
8769 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
8771 clearFilter : function(suppressEvent){
8772 if(this.snapshot && this.snapshot != this.data){
8773 this.data = this.snapshot;
8774 delete this.snapshot;
8775 if(suppressEvent !== true){
8776 this.fireEvent("datachanged", this);
8782 afterEdit : function(record){
8783 if(this.modified.indexOf(record) == -1){
8784 this.modified.push(record);
8786 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
8790 afterReject : function(record){
8791 this.modified.remove(record);
8792 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
8796 afterCommit : function(record){
8797 this.modified.remove(record);
8798 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
8802 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
8803 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
8805 commitChanges : function(){
8806 var m = this.modified.slice(0);
8808 for(var i = 0, len = m.length; i < len; i++){
8814 * Cancel outstanding changes on all changed records.
8816 rejectChanges : function(){
8817 var m = this.modified.slice(0);
8819 for(var i = 0, len = m.length; i < len; i++){
8824 onMetaChange : function(meta, rtype, o){
8825 this.recordType = rtype;
8826 this.fields = rtype.prototype.fields;
8827 delete this.snapshot;
8828 this.sortInfo = meta.sortInfo || this.sortInfo;
8830 this.fireEvent('metachange', this, this.reader.meta);
8833 moveIndex : function(data, type)
8835 var index = this.indexOf(data);
8837 var newIndex = index + type;
8841 this.insert(newIndex, data);
8846 * Ext JS Library 1.1.1
8847 * Copyright(c) 2006-2007, Ext JS, LLC.
8849 * Originally Released Under LGPL - original licence link has changed is not relivant.
8852 * <script type="text/javascript">
8856 * @class Roo.data.SimpleStore
8857 * @extends Roo.data.Store
8858 * Small helper class to make creating Stores from Array data easier.
8859 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
8860 * @cfg {Array} fields An array of field definition objects, or field name strings.
8861 * @cfg {Array} data The multi-dimensional array of data
8863 * @param {Object} config
8865 Roo.data.SimpleStore = function(config){
8866 Roo.data.SimpleStore.superclass.constructor.call(this, {
8868 reader: new Roo.data.ArrayReader({
8871 Roo.data.Record.create(config.fields)
8873 proxy : new Roo.data.MemoryProxy(config.data)
8877 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
8879 * Ext JS Library 1.1.1
8880 * Copyright(c) 2006-2007, Ext JS, LLC.
8882 * Originally Released Under LGPL - original licence link has changed is not relivant.
8885 * <script type="text/javascript">
8890 * @extends Roo.data.Store
8891 * @class Roo.data.JsonStore
8892 * Small helper class to make creating Stores for JSON data easier. <br/>
8894 var store = new Roo.data.JsonStore({
8895 url: 'get-images.php',
8897 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
8900 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
8901 * JsonReader and HttpProxy (unless inline data is provided).</b>
8902 * @cfg {Array} fields An array of field definition objects, or field name strings.
8904 * @param {Object} config
8906 Roo.data.JsonStore = function(c){
8907 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
8908 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
8909 reader: new Roo.data.JsonReader(c, c.fields)
8912 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
8914 * Ext JS Library 1.1.1
8915 * Copyright(c) 2006-2007, Ext JS, LLC.
8917 * Originally Released Under LGPL - original licence link has changed is not relivant.
8920 * <script type="text/javascript">
8924 Roo.data.Field = function(config){
8925 if(typeof config == "string"){
8926 config = {name: config};
8928 Roo.apply(this, config);
8934 var st = Roo.data.SortTypes;
8935 // named sortTypes are supported, here we look them up
8936 if(typeof this.sortType == "string"){
8937 this.sortType = st[this.sortType];
8940 // set default sortType for strings and dates
8944 this.sortType = st.asUCString;
8947 this.sortType = st.asDate;
8950 this.sortType = st.none;
8955 var stripRe = /[\$,%]/g;
8957 // prebuilt conversion function for this field, instead of
8958 // switching every time we're reading a value
8960 var cv, dateFormat = this.dateFormat;
8965 cv = function(v){ return v; };
8968 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
8972 return v !== undefined && v !== null && v !== '' ?
8973 parseInt(String(v).replace(stripRe, ""), 10) : '';
8978 return v !== undefined && v !== null && v !== '' ?
8979 parseFloat(String(v).replace(stripRe, ""), 10) : '';
8984 cv = function(v){ return v === true || v === "true" || v == 1; };
8991 if(v instanceof Date){
8995 if(dateFormat == "timestamp"){
8996 return new Date(v*1000);
8998 return Date.parseDate(v, dateFormat);
9000 var parsed = Date.parse(v);
9001 return parsed ? new Date(parsed) : null;
9010 Roo.data.Field.prototype = {
9018 * Ext JS Library 1.1.1
9019 * Copyright(c) 2006-2007, Ext JS, LLC.
9021 * Originally Released Under LGPL - original licence link has changed is not relivant.
9024 * <script type="text/javascript">
9027 // Base class for reading structured data from a data source. This class is intended to be
9028 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9031 * @class Roo.data.DataReader
9032 * Base class for reading structured data from a data source. This class is intended to be
9033 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9036 Roo.data.DataReader = function(meta, recordType){
9040 this.recordType = recordType instanceof Array ?
9041 Roo.data.Record.create(recordType) : recordType;
9044 Roo.data.DataReader.prototype = {
9046 * Create an empty record
9047 * @param {Object} data (optional) - overlay some values
9048 * @return {Roo.data.Record} record created.
9050 newRow : function(d) {
9052 this.recordType.prototype.fields.each(function(c) {
9054 case 'int' : da[c.name] = 0; break;
9055 case 'date' : da[c.name] = new Date(); break;
9056 case 'float' : da[c.name] = 0.0; break;
9057 case 'boolean' : da[c.name] = false; break;
9058 default : da[c.name] = ""; break;
9062 return new this.recordType(Roo.apply(da, d));
9067 * Ext JS Library 1.1.1
9068 * Copyright(c) 2006-2007, Ext JS, LLC.
9070 * Originally Released Under LGPL - original licence link has changed is not relivant.
9073 * <script type="text/javascript">
9077 * @class Roo.data.DataProxy
9078 * @extends Roo.data.Observable
9079 * This class is an abstract base class for implementations which provide retrieval of
9080 * unformatted data objects.<br>
9082 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9083 * (of the appropriate type which knows how to parse the data object) to provide a block of
9084 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9086 * Custom implementations must implement the load method as described in
9087 * {@link Roo.data.HttpProxy#load}.
9089 Roo.data.DataProxy = function(){
9093 * Fires before a network request is made to retrieve a data object.
9094 * @param {Object} This DataProxy object.
9095 * @param {Object} params The params parameter to the load function.
9100 * Fires before the load method's callback is called.
9101 * @param {Object} This DataProxy object.
9102 * @param {Object} o The data object.
9103 * @param {Object} arg The callback argument object passed to the load function.
9107 * @event loadexception
9108 * Fires if an Exception occurs during data retrieval.
9109 * @param {Object} This DataProxy object.
9110 * @param {Object} o The data object.
9111 * @param {Object} arg The callback argument object passed to the load function.
9112 * @param {Object} e The Exception.
9114 loadexception : true
9116 Roo.data.DataProxy.superclass.constructor.call(this);
9119 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9122 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9126 * Ext JS Library 1.1.1
9127 * Copyright(c) 2006-2007, Ext JS, LLC.
9129 * Originally Released Under LGPL - original licence link has changed is not relivant.
9132 * <script type="text/javascript">
9135 * @class Roo.data.MemoryProxy
9136 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9137 * to the Reader when its load method is called.
9139 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9141 Roo.data.MemoryProxy = function(data){
9145 Roo.data.MemoryProxy.superclass.constructor.call(this);
9149 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9151 * Load data from the requested source (in this case an in-memory
9152 * data object passed to the constructor), read the data object into
9153 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9154 * process that block using the passed callback.
9155 * @param {Object} params This parameter is not used by the MemoryProxy class.
9156 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9157 * object into a block of Roo.data.Records.
9158 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9159 * The function must be passed <ul>
9160 * <li>The Record block object</li>
9161 * <li>The "arg" argument from the load function</li>
9162 * <li>A boolean success indicator</li>
9164 * @param {Object} scope The scope in which to call the callback
9165 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9167 load : function(params, reader, callback, scope, arg){
9168 params = params || {};
9171 result = reader.readRecords(this.data);
9173 this.fireEvent("loadexception", this, arg, null, e);
9174 callback.call(scope, null, arg, false);
9177 callback.call(scope, result, arg, true);
9181 update : function(params, records){
9186 * Ext JS Library 1.1.1
9187 * Copyright(c) 2006-2007, Ext JS, LLC.
9189 * Originally Released Under LGPL - original licence link has changed is not relivant.
9192 * <script type="text/javascript">
9195 * @class Roo.data.HttpProxy
9196 * @extends Roo.data.DataProxy
9197 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9198 * configured to reference a certain URL.<br><br>
9200 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9201 * from which the running page was served.<br><br>
9203 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9205 * Be aware that to enable the browser to parse an XML document, the server must set
9206 * the Content-Type header in the HTTP response to "text/xml".
9208 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9209 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9210 * will be used to make the request.
9212 Roo.data.HttpProxy = function(conn){
9213 Roo.data.HttpProxy.superclass.constructor.call(this);
9214 // is conn a conn config or a real conn?
9216 this.useAjax = !conn || !conn.events;
9220 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9221 // thse are take from connection...
9224 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9227 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9228 * extra parameters to each request made by this object. (defaults to undefined)
9231 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9232 * to each request made by this object. (defaults to undefined)
9235 * @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)
9238 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9241 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9247 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9251 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9252 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9253 * a finer-grained basis than the DataProxy events.
9255 getConnection : function(){
9256 return this.useAjax ? Roo.Ajax : this.conn;
9260 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9261 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9262 * process that block using the passed callback.
9263 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9264 * for the request to the remote server.
9265 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9266 * object into a block of Roo.data.Records.
9267 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9268 * The function must be passed <ul>
9269 * <li>The Record block object</li>
9270 * <li>The "arg" argument from the load function</li>
9271 * <li>A boolean success indicator</li>
9273 * @param {Object} scope The scope in which to call the callback
9274 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9276 load : function(params, reader, callback, scope, arg){
9277 if(this.fireEvent("beforeload", this, params) !== false){
9279 params : params || {},
9281 callback : callback,
9286 callback : this.loadResponse,
9290 Roo.applyIf(o, this.conn);
9291 if(this.activeRequest){
9292 Roo.Ajax.abort(this.activeRequest);
9294 this.activeRequest = Roo.Ajax.request(o);
9296 this.conn.request(o);
9299 callback.call(scope||this, null, arg, false);
9304 loadResponse : function(o, success, response){
9305 delete this.activeRequest;
9307 this.fireEvent("loadexception", this, o, response);
9308 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9313 result = o.reader.read(response);
9315 this.fireEvent("loadexception", this, o, response, e);
9316 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9320 this.fireEvent("load", this, o, o.request.arg);
9321 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9325 update : function(dataSet){
9330 updateResponse : function(dataSet){
9335 * Ext JS Library 1.1.1
9336 * Copyright(c) 2006-2007, Ext JS, LLC.
9338 * Originally Released Under LGPL - original licence link has changed is not relivant.
9341 * <script type="text/javascript">
9345 * @class Roo.data.ScriptTagProxy
9346 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9347 * other than the originating domain of the running page.<br><br>
9349 * <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
9350 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9352 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9353 * source code that is used as the source inside a <script> tag.<br><br>
9355 * In order for the browser to process the returned data, the server must wrap the data object
9356 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9357 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9358 * depending on whether the callback name was passed:
9361 boolean scriptTag = false;
9362 String cb = request.getParameter("callback");
9365 response.setContentType("text/javascript");
9367 response.setContentType("application/x-json");
9369 Writer out = response.getWriter();
9371 out.write(cb + "(");
9373 out.print(dataBlock.toJsonString());
9380 * @param {Object} config A configuration object.
9382 Roo.data.ScriptTagProxy = function(config){
9383 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9384 Roo.apply(this, config);
9385 this.head = document.getElementsByTagName("head")[0];
9388 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9390 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9392 * @cfg {String} url The URL from which to request the data object.
9395 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9399 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9400 * the server the name of the callback function set up by the load call to process the returned data object.
9401 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9402 * javascript output which calls this named function passing the data object as its only parameter.
9404 callbackParam : "callback",
9406 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9407 * name to the request.
9412 * Load data from the configured URL, read the data object into
9413 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9414 * process that block using the passed callback.
9415 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9416 * for the request to the remote server.
9417 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9418 * object into a block of Roo.data.Records.
9419 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9420 * The function must be passed <ul>
9421 * <li>The Record block object</li>
9422 * <li>The "arg" argument from the load function</li>
9423 * <li>A boolean success indicator</li>
9425 * @param {Object} scope The scope in which to call the callback
9426 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9428 load : function(params, reader, callback, scope, arg){
9429 if(this.fireEvent("beforeload", this, params) !== false){
9431 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9434 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9436 url += "&_dc=" + (new Date().getTime());
9438 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9441 cb : "stcCallback"+transId,
9442 scriptId : "stcScript"+transId,
9446 callback : callback,
9452 window[trans.cb] = function(o){
9453 conn.handleResponse(o, trans);
9456 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9458 if(this.autoAbort !== false){
9462 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9464 var script = document.createElement("script");
9465 script.setAttribute("src", url);
9466 script.setAttribute("type", "text/javascript");
9467 script.setAttribute("id", trans.scriptId);
9468 this.head.appendChild(script);
9472 callback.call(scope||this, null, arg, false);
9477 isLoading : function(){
9478 return this.trans ? true : false;
9482 * Abort the current server request.
9485 if(this.isLoading()){
9486 this.destroyTrans(this.trans);
9491 destroyTrans : function(trans, isLoaded){
9492 this.head.removeChild(document.getElementById(trans.scriptId));
9493 clearTimeout(trans.timeoutId);
9495 window[trans.cb] = undefined;
9497 delete window[trans.cb];
9500 // if hasn't been loaded, wait for load to remove it to prevent script error
9501 window[trans.cb] = function(){
9502 window[trans.cb] = undefined;
9504 delete window[trans.cb];
9511 handleResponse : function(o, trans){
9513 this.destroyTrans(trans, true);
9516 result = trans.reader.readRecords(o);
9518 this.fireEvent("loadexception", this, o, trans.arg, e);
9519 trans.callback.call(trans.scope||window, null, trans.arg, false);
9522 this.fireEvent("load", this, o, trans.arg);
9523 trans.callback.call(trans.scope||window, result, trans.arg, true);
9527 handleFailure : function(trans){
9529 this.destroyTrans(trans, false);
9530 this.fireEvent("loadexception", this, null, trans.arg);
9531 trans.callback.call(trans.scope||window, null, trans.arg, false);
9535 * Ext JS Library 1.1.1
9536 * Copyright(c) 2006-2007, Ext JS, LLC.
9538 * Originally Released Under LGPL - original licence link has changed is not relivant.
9541 * <script type="text/javascript">
9545 * @class Roo.data.JsonReader
9546 * @extends Roo.data.DataReader
9547 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9548 * based on mappings in a provided Roo.data.Record constructor.
9550 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9551 * in the reply previously.
9556 var RecordDef = Roo.data.Record.create([
9557 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
9558 {name: 'occupation'} // This field will use "occupation" as the mapping.
9560 var myReader = new Roo.data.JsonReader({
9561 totalProperty: "results", // The property which contains the total dataset size (optional)
9562 root: "rows", // The property which contains an Array of row objects
9563 id: "id" // The property within each row object that provides an ID for the record (optional)
9567 * This would consume a JSON file like this:
9569 { 'results': 2, 'rows': [
9570 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9571 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9574 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9575 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9576 * paged from the remote server.
9577 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9578 * @cfg {String} root name of the property which contains the Array of row objects.
9579 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9581 * Create a new JsonReader
9582 * @param {Object} meta Metadata configuration options
9583 * @param {Object} recordType Either an Array of field definition objects,
9584 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9586 Roo.data.JsonReader = function(meta, recordType){
9589 // set some defaults:
9591 totalProperty: 'total',
9592 successProperty : 'success',
9597 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9599 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9602 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
9603 * Used by Store query builder to append _requestMeta to params.
9606 metaFromRemote : false,
9608 * This method is only used by a DataProxy which has retrieved data from a remote server.
9609 * @param {Object} response The XHR object which contains the JSON data in its responseText.
9610 * @return {Object} data A data block which is used by an Roo.data.Store object as
9611 * a cache of Roo.data.Records.
9613 read : function(response){
9614 var json = response.responseText;
9616 var o = /* eval:var:o */ eval("("+json+")");
9618 throw {message: "JsonReader.read: Json object not found"};
9624 this.metaFromRemote = true;
9625 this.meta = o.metaData;
9626 this.recordType = Roo.data.Record.create(o.metaData.fields);
9627 this.onMetaChange(this.meta, this.recordType, o);
9629 return this.readRecords(o);
9632 // private function a store will implement
9633 onMetaChange : function(meta, recordType, o){
9640 simpleAccess: function(obj, subsc) {
9647 getJsonAccessor: function(){
9649 return function(expr) {
9651 return(re.test(expr))
9652 ? new Function("obj", "return obj." + expr)
9662 * Create a data block containing Roo.data.Records from an XML document.
9663 * @param {Object} o An object which contains an Array of row objects in the property specified
9664 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
9665 * which contains the total size of the dataset.
9666 * @return {Object} data A data block which is used by an Roo.data.Store object as
9667 * a cache of Roo.data.Records.
9669 readRecords : function(o){
9671 * After any data loads, the raw JSON data is available for further custom processing.
9675 var s = this.meta, Record = this.recordType,
9676 f = Record.prototype.fields, fi = f.items, fl = f.length;
9678 // Generate extraction functions for the totalProperty, the root, the id, and for each field
9680 if(s.totalProperty) {
9681 this.getTotal = this.getJsonAccessor(s.totalProperty);
9683 if(s.successProperty) {
9684 this.getSuccess = this.getJsonAccessor(s.successProperty);
9686 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
9688 var g = this.getJsonAccessor(s.id);
9689 this.getId = function(rec) {
9691 return (r === undefined || r === "") ? null : r;
9694 this.getId = function(){return null;};
9697 for(var jj = 0; jj < fl; jj++){
9699 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
9700 this.ef[jj] = this.getJsonAccessor(map);
9704 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
9705 if(s.totalProperty){
9706 var vt = parseInt(this.getTotal(o), 10);
9711 if(s.successProperty){
9712 var vs = this.getSuccess(o);
9713 if(vs === false || vs === 'false'){
9718 for(var i = 0; i < c; i++){
9721 var id = this.getId(n);
9722 for(var j = 0; j < fl; j++){
9724 var v = this.ef[j](n);
9726 Roo.log('missing convert for ' + f.name);
9730 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
9732 var record = new Record(values, id);
9734 records[i] = record;
9740 totalRecords : totalRecords
9745 * Ext JS Library 1.1.1
9746 * Copyright(c) 2006-2007, Ext JS, LLC.
9748 * Originally Released Under LGPL - original licence link has changed is not relivant.
9751 * <script type="text/javascript">
9755 * @class Roo.data.ArrayReader
9756 * @extends Roo.data.DataReader
9757 * Data reader class to create an Array of Roo.data.Record objects from an Array.
9758 * Each element of that Array represents a row of data fields. The
9759 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
9760 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
9764 var RecordDef = Roo.data.Record.create([
9765 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
9766 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
9768 var myReader = new Roo.data.ArrayReader({
9769 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
9773 * This would consume an Array like this:
9775 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
9777 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
9779 * Create a new JsonReader
9780 * @param {Object} meta Metadata configuration options.
9781 * @param {Object} recordType Either an Array of field definition objects
9782 * as specified to {@link Roo.data.Record#create},
9783 * or an {@link Roo.data.Record} object
9784 * created using {@link Roo.data.Record#create}.
9786 Roo.data.ArrayReader = function(meta, recordType){
9787 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
9790 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
9792 * Create a data block containing Roo.data.Records from an XML document.
9793 * @param {Object} o An Array of row objects which represents the dataset.
9794 * @return {Object} data A data block which is used by an Roo.data.Store object as
9795 * a cache of Roo.data.Records.
9797 readRecords : function(o){
9798 var sid = this.meta ? this.meta.id : null;
9799 var recordType = this.recordType, fields = recordType.prototype.fields;
9802 for(var i = 0; i < root.length; i++){
9805 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
9806 for(var j = 0, jlen = fields.length; j < jlen; j++){
9807 var f = fields.items[j];
9808 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
9809 var v = n[k] !== undefined ? n[k] : f.defaultValue;
9813 var record = new recordType(values, id);
9815 records[records.length] = record;
9819 totalRecords : records.length
9828 * @class Roo.bootstrap.ComboBox
9829 * @extends Roo.bootstrap.TriggerField
9830 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
9831 * @cfg {Boolean} append (true|false) default false
9832 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
9833 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
9834 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
9836 * Create a new ComboBox.
9837 * @param {Object} config Configuration options
9839 Roo.bootstrap.ComboBox = function(config){
9840 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
9844 * Fires when the dropdown list is expanded
9845 * @param {Roo.bootstrap.ComboBox} combo This combo box
9850 * Fires when the dropdown list is collapsed
9851 * @param {Roo.bootstrap.ComboBox} combo This combo box
9855 * @event beforeselect
9856 * Fires before a list item is selected. Return false to cancel the selection.
9857 * @param {Roo.bootstrap.ComboBox} combo This combo box
9858 * @param {Roo.data.Record} record The data record returned from the underlying store
9859 * @param {Number} index The index of the selected item in the dropdown list
9861 'beforeselect' : true,
9864 * Fires when a list item is selected
9865 * @param {Roo.bootstrap.ComboBox} combo This combo box
9866 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
9867 * @param {Number} index The index of the selected item in the dropdown list
9871 * @event beforequery
9872 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
9873 * The event object passed has these properties:
9874 * @param {Roo.bootstrap.ComboBox} combo This combo box
9875 * @param {String} query The query
9876 * @param {Boolean} forceAll true to force "all" query
9877 * @param {Boolean} cancel true to cancel the query
9878 * @param {Object} e The query event object
9880 'beforequery': true,
9883 * Fires when the 'add' icon is pressed (add a listener to enable add button)
9884 * @param {Roo.bootstrap.ComboBox} combo This combo box
9889 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
9890 * @param {Roo.bootstrap.ComboBox} combo This combo box
9891 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
9896 * Fires when the remove value from the combobox array
9897 * @param {Roo.bootstrap.ComboBox} combo This combo box
9904 this.tickItems = [];
9906 this.selectedIndex = -1;
9907 if(this.mode == 'local'){
9908 if(config.queryDelay === undefined){
9909 this.queryDelay = 10;
9911 if(config.minChars === undefined){
9917 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
9920 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
9921 * rendering into an Roo.Editor, defaults to false)
9924 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
9925 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
9928 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
9931 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
9932 * the dropdown list (defaults to undefined, with no header element)
9936 * @cfg {String/Roo.Template} tpl The template to use to render the output
9940 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
9942 listWidth: undefined,
9944 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
9945 * mode = 'remote' or 'text' if mode = 'local')
9947 displayField: undefined,
9949 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
9950 * mode = 'remote' or 'value' if mode = 'local').
9951 * Note: use of a valueField requires the user make a selection
9952 * in order for a value to be mapped.
9954 valueField: undefined,
9958 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
9959 * field's data value (defaults to the underlying DOM element's name)
9961 hiddenName: undefined,
9963 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
9967 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
9969 selectedClass: 'active',
9972 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
9976 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
9977 * anchor positions (defaults to 'tl-bl')
9979 listAlign: 'tl-bl?',
9981 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
9985 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
9986 * query specified by the allQuery config option (defaults to 'query')
9988 triggerAction: 'query',
9990 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
9991 * (defaults to 4, does not apply if editable = false)
9995 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
9996 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10000 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10001 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10005 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10006 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10010 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10011 * when editable = true (defaults to false)
10013 selectOnFocus:false,
10015 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10017 queryParam: 'query',
10019 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10020 * when mode = 'remote' (defaults to 'Loading...')
10022 loadingText: 'Loading...',
10024 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10028 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10032 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10033 * traditional select (defaults to true)
10037 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10041 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10045 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10046 * listWidth has a higher value)
10050 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10051 * allow the user to set arbitrary text into the field (defaults to false)
10053 forceSelection:false,
10055 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10056 * if typeAhead = true (defaults to 250)
10058 typeAheadDelay : 250,
10060 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10061 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10063 valueNotFoundText : undefined,
10065 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10067 blockFocus : false,
10070 * @cfg {Boolean} disableClear Disable showing of clear button.
10072 disableClear : false,
10074 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10076 alwaysQuery : false,
10079 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10093 btnPosition : 'right',
10095 // element that contains real text value.. (when hidden is used..)
10097 getAutoCreate : function()
10104 if(!this.tickable){
10105 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10110 * ComboBox with tickable selections
10113 var align = this.labelAlign || this.parentLabelAlign();
10116 cls : 'form-group roo-combobox-tickable' //input-group
10122 cls : 'tickable-buttons',
10127 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10134 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10141 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10148 Roo.each(buttons.cn, function(c){
10150 c.cls += ' btn-' + _this.size;
10153 if (_this.disabled) {
10164 cls: 'form-hidden-field'
10168 cls: 'select2-choices',
10172 cls: 'select2-search-field',
10184 cls: 'select2-container input-group select2-container-multi',
10189 cls: 'typeahead typeahead-long dropdown-menu',
10190 style: 'display:none; max-height:' + this.maxHeight + 'px;'
10195 if (align ==='left' && this.fieldLabel.length) {
10197 Roo.log("left and has label");
10203 cls : 'control-label col-sm-' + this.labelWidth,
10204 html : this.fieldLabel
10208 cls : "col-sm-" + (12 - this.labelWidth),
10215 } else if ( this.fieldLabel.length) {
10221 //cls : 'input-group-addon',
10222 html : this.fieldLabel
10232 Roo.log(" no label && no align");
10239 ['xs','sm','md','lg'].map(function(size){
10240 if (settings[size]) {
10241 cfg.cls += ' col-' + size + '-' + settings[size];
10250 initEvents: function()
10254 throw "can not find store for combo";
10256 this.store = Roo.factory(this.store, Roo.data);
10259 this.initTickableEvnets();
10263 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10266 if(this.hiddenName){
10268 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10270 this.hiddenField.dom.value =
10271 this.hiddenValue !== undefined ? this.hiddenValue :
10272 this.value !== undefined ? this.value : '';
10274 // prevent input submission
10275 this.el.dom.removeAttribute('name');
10276 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10281 // this.el.dom.setAttribute('autocomplete', 'off');
10284 var cls = 'x-combo-list';
10285 this.list = this.el.select('ul.dropdown-menu',true).first();
10287 //this.list = new Roo.Layer({
10288 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10294 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10295 _this.list.setWidth(lw);
10298 this.list.on('mouseover', this.onViewOver, this);
10299 this.list.on('mousemove', this.onViewMove, this);
10301 this.list.on('scroll', this.onViewScroll, this);
10304 this.list.swallowEvent('mousewheel');
10305 this.assetHeight = 0;
10308 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10309 this.assetHeight += this.header.getHeight();
10312 this.innerList = this.list.createChild({cls:cls+'-inner'});
10313 this.innerList.on('mouseover', this.onViewOver, this);
10314 this.innerList.on('mousemove', this.onViewMove, this);
10315 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10317 if(this.allowBlank && !this.pageSize && !this.disableClear){
10318 this.footer = this.list.createChild({cls:cls+'-ft'});
10319 this.pageTb = new Roo.Toolbar(this.footer);
10323 this.footer = this.list.createChild({cls:cls+'-ft'});
10324 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10325 {pageSize: this.pageSize});
10329 if (this.pageTb && this.allowBlank && !this.disableClear) {
10331 this.pageTb.add(new Roo.Toolbar.Fill(), {
10332 cls: 'x-btn-icon x-btn-clear',
10334 handler: function()
10337 _this.clearValue();
10338 _this.onSelect(false, -1);
10343 this.assetHeight += this.footer.getHeight();
10348 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10351 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
10352 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10354 //this.view.wrapEl.setDisplayed(false);
10355 this.view.on('click', this.onViewClick, this);
10359 this.store.on('beforeload', this.onBeforeLoad, this);
10360 this.store.on('load', this.onLoad, this);
10361 this.store.on('loadexception', this.onLoadException, this);
10363 if(this.resizable){
10364 this.resizer = new Roo.Resizable(this.list, {
10365 pinned:true, handles:'se'
10367 this.resizer.on('resize', function(r, w, h){
10368 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10369 this.listWidth = w;
10370 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10371 this.restrictHeight();
10373 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10376 if(!this.editable){
10377 this.editable = true;
10378 this.setEditable(false);
10383 if (typeof(this.events.add.listeners) != 'undefined') {
10385 this.addicon = this.wrap.createChild(
10386 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10388 this.addicon.on('click', function(e) {
10389 this.fireEvent('add', this);
10392 if (typeof(this.events.edit.listeners) != 'undefined') {
10394 this.editicon = this.wrap.createChild(
10395 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10396 if (this.addicon) {
10397 this.editicon.setStyle('margin-left', '40px');
10399 this.editicon.on('click', function(e) {
10401 // we fire even if inothing is selected..
10402 this.fireEvent('edit', this, this.lastData );
10408 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10409 "up" : function(e){
10410 this.inKeyMode = true;
10414 "down" : function(e){
10415 if(!this.isExpanded()){
10416 this.onTriggerClick();
10418 this.inKeyMode = true;
10423 "enter" : function(e){
10424 // this.onViewClick();
10428 if(this.fireEvent("specialkey", this, e)){
10429 this.onViewClick(false);
10435 "esc" : function(e){
10439 "tab" : function(e){
10442 if(this.fireEvent("specialkey", this, e)){
10443 this.onViewClick(false);
10451 doRelay : function(foo, bar, hname){
10452 if(hname == 'down' || this.scope.isExpanded()){
10453 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10462 this.queryDelay = Math.max(this.queryDelay || 10,
10463 this.mode == 'local' ? 10 : 250);
10466 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10468 if(this.typeAhead){
10469 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10471 if(this.editable !== false){
10472 this.inputEl().on("keyup", this.onKeyUp, this);
10474 if(this.forceSelection){
10475 this.inputEl().on('blur', this.doForce, this);
10479 this.choices = this.el.select('ul.select2-choices', true).first();
10480 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10484 initTickableEvnets: function()
10486 if(this.hiddenName){
10488 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10490 this.hiddenField.dom.value =
10491 this.hiddenValue !== undefined ? this.hiddenValue :
10492 this.value !== undefined ? this.value : '';
10494 // prevent input submission
10495 this.el.dom.removeAttribute('name');
10496 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10501 this.list = this.el.select('ul.dropdown-menu',true).first();
10503 this.choices = this.el.select('ul.select2-choices', true).first();
10504 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10506 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10507 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10509 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10510 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10512 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10513 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10515 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10516 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10517 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10520 this.cancelBtn.hide();
10525 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10526 _this.list.setWidth(lw);
10529 this.list.on('mouseover', this.onViewOver, this);
10530 this.list.on('mousemove', this.onViewMove, this);
10532 this.list.on('scroll', this.onViewScroll, this);
10535 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>';
10538 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
10539 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10542 //this.view.wrapEl.setDisplayed(false);
10543 this.view.on('click', this.onViewClick, this);
10547 this.store.on('beforeload', this.onBeforeLoad, this);
10548 this.store.on('load', this.onLoad, this);
10549 this.store.on('loadexception', this.onLoadException, this);
10551 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
10552 // "up" : function(e){
10553 // this.inKeyMode = true;
10554 // this.selectPrev();
10557 // "down" : function(e){
10558 // if(!this.isExpanded()){
10559 // this.onTriggerClick();
10561 // this.inKeyMode = true;
10562 // this.selectNext();
10566 // "enter" : function(e){
10567 //// this.onViewClick();
10569 // this.collapse();
10571 // if(this.fireEvent("specialkey", this, e)){
10572 // this.onViewClick(false);
10578 // "esc" : function(e){
10579 // this.collapse();
10582 // "tab" : function(e){
10583 // this.collapse();
10585 // if(this.fireEvent("specialkey", this, e)){
10586 // this.onViewClick(false);
10594 // doRelay : function(foo, bar, hname){
10595 // if(hname == 'down' || this.scope.isExpanded()){
10596 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10601 // forceKeyDown: true
10605 this.queryDelay = Math.max(this.queryDelay || 10,
10606 this.mode == 'local' ? 10 : 250);
10609 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10611 if(this.typeAhead){
10612 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10616 onDestroy : function(){
10618 this.view.setStore(null);
10619 this.view.el.removeAllListeners();
10620 this.view.el.remove();
10621 this.view.purgeListeners();
10624 this.list.dom.innerHTML = '';
10628 this.store.un('beforeload', this.onBeforeLoad, this);
10629 this.store.un('load', this.onLoad, this);
10630 this.store.un('loadexception', this.onLoadException, this);
10632 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
10636 fireKey : function(e){
10637 if(e.isNavKeyPress() && !this.list.isVisible()){
10638 this.fireEvent("specialkey", this, e);
10643 onResize: function(w, h){
10644 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
10646 // if(typeof w != 'number'){
10647 // // we do not handle it!?!?
10650 // var tw = this.trigger.getWidth();
10651 // // tw += this.addicon ? this.addicon.getWidth() : 0;
10652 // // tw += this.editicon ? this.editicon.getWidth() : 0;
10654 // this.inputEl().setWidth( this.adjustWidth('input', x));
10656 // //this.trigger.setStyle('left', x+'px');
10658 // if(this.list && this.listWidth === undefined){
10659 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
10660 // this.list.setWidth(lw);
10661 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10669 * Allow or prevent the user from directly editing the field text. If false is passed,
10670 * the user will only be able to select from the items defined in the dropdown list. This method
10671 * is the runtime equivalent of setting the 'editable' config option at config time.
10672 * @param {Boolean} value True to allow the user to directly edit the field text
10674 setEditable : function(value){
10675 if(value == this.editable){
10678 this.editable = value;
10680 this.inputEl().dom.setAttribute('readOnly', true);
10681 this.inputEl().on('mousedown', this.onTriggerClick, this);
10682 this.inputEl().addClass('x-combo-noedit');
10684 this.inputEl().dom.setAttribute('readOnly', false);
10685 this.inputEl().un('mousedown', this.onTriggerClick, this);
10686 this.inputEl().removeClass('x-combo-noedit');
10692 onBeforeLoad : function(combo,opts){
10693 if(!this.hasFocus){
10697 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
10699 this.restrictHeight();
10700 this.selectedIndex = -1;
10704 onLoad : function(){
10706 this.hasQuery = false;
10708 if(!this.hasFocus){
10712 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10713 this.loading.hide();
10716 if(this.store.getCount() > 0){
10718 this.restrictHeight();
10719 if(this.lastQuery == this.allQuery){
10720 if(this.editable && !this.tickable){
10721 this.inputEl().dom.select();
10723 if(!this.selectByValue(this.value, true) && this.autoFocus){
10724 this.select(0, true);
10727 if(this.autoFocus){
10730 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
10731 this.taTask.delay(this.typeAheadDelay);
10735 this.onEmptyResults();
10741 onLoadException : function()
10743 this.hasQuery = false;
10745 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10746 this.loading.hide();
10750 Roo.log(this.store.reader.jsonData);
10751 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
10753 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
10759 onTypeAhead : function(){
10760 if(this.store.getCount() > 0){
10761 var r = this.store.getAt(0);
10762 var newValue = r.data[this.displayField];
10763 var len = newValue.length;
10764 var selStart = this.getRawValue().length;
10766 if(selStart != len){
10767 this.setRawValue(newValue);
10768 this.selectText(selStart, newValue.length);
10774 onSelect : function(record, index){
10776 if(this.fireEvent('beforeselect', this, record, index) !== false){
10778 this.setFromData(index > -1 ? record.data : false);
10781 this.fireEvent('select', this, record, index);
10786 * Returns the currently selected field value or empty string if no value is set.
10787 * @return {String} value The selected value
10789 getValue : function(){
10792 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
10795 if(this.valueField){
10796 return typeof this.value != 'undefined' ? this.value : '';
10798 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
10803 * Clears any text/value currently set in the field
10805 clearValue : function(){
10806 if(this.hiddenField){
10807 this.hiddenField.dom.value = '';
10810 this.setRawValue('');
10811 this.lastSelectionText = '';
10816 * Sets the specified value into the field. If the value finds a match, the corresponding record text
10817 * will be displayed in the field. If the value does not match the data value of an existing item,
10818 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
10819 * Otherwise the field will be blank (although the value will still be set).
10820 * @param {String} value The value to match
10822 setValue : function(v){
10829 if(this.valueField){
10830 var r = this.findRecord(this.valueField, v);
10832 text = r.data[this.displayField];
10833 }else if(this.valueNotFoundText !== undefined){
10834 text = this.valueNotFoundText;
10837 this.lastSelectionText = text;
10838 if(this.hiddenField){
10839 this.hiddenField.dom.value = v;
10841 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
10845 * @property {Object} the last set data for the element
10850 * Sets the value of the field based on a object which is related to the record format for the store.
10851 * @param {Object} value the value to set as. or false on reset?
10853 setFromData : function(o){
10860 var dv = ''; // display value
10861 var vv = ''; // value value..
10863 if (this.displayField) {
10864 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
10866 // this is an error condition!!!
10867 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
10870 if(this.valueField){
10871 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
10874 if(this.hiddenField){
10875 this.hiddenField.dom.value = vv;
10877 this.lastSelectionText = dv;
10878 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
10882 // no hidden field.. - we store the value in 'value', but still display
10883 // display field!!!!
10884 this.lastSelectionText = dv;
10885 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
10891 reset : function(){
10892 // overridden so that last data is reset..
10893 this.setValue(this.originalValue);
10894 this.clearInvalid();
10895 this.lastData = false;
10897 this.view.clearSelections();
10901 findRecord : function(prop, value){
10903 if(this.store.getCount() > 0){
10904 this.store.each(function(r){
10905 if(r.data[prop] == value){
10915 getName: function()
10917 // returns hidden if it's set..
10918 if (!this.rendered) {return ''};
10919 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
10923 onViewMove : function(e, t){
10924 this.inKeyMode = false;
10928 onViewOver : function(e, t){
10929 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
10932 var item = this.view.findItemFromChild(t);
10935 var index = this.view.indexOf(item);
10936 this.select(index, false);
10941 onViewClick : function(view, doFocus, el, e)
10943 var index = this.view.getSelectedIndexes()[0];
10945 var r = this.store.getAt(index);
10949 if(e.getTarget().nodeName.toLowerCase() != 'input'){
10956 Roo.each(this.tickItems, function(v,k){
10958 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
10959 _this.tickItems.splice(k, 1);
10969 this.tickItems.push(r.data);
10974 this.onSelect(r, index);
10976 if(doFocus !== false && !this.blockFocus){
10977 this.inputEl().focus();
10982 restrictHeight : function(){
10983 //this.innerList.dom.style.height = '';
10984 //var inner = this.innerList.dom;
10985 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
10986 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
10987 //this.list.beginUpdate();
10988 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
10989 this.list.alignTo(this.inputEl(), this.listAlign);
10990 //this.list.endUpdate();
10994 onEmptyResults : function(){
10999 * Returns true if the dropdown list is expanded, else false.
11001 isExpanded : function(){
11002 return this.list.isVisible();
11006 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11007 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11008 * @param {String} value The data value of the item to select
11009 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11010 * selected item if it is not currently in view (defaults to true)
11011 * @return {Boolean} True if the value matched an item in the list, else false
11013 selectByValue : function(v, scrollIntoView){
11014 if(v !== undefined && v !== null){
11015 var r = this.findRecord(this.valueField || this.displayField, v);
11017 this.select(this.store.indexOf(r), scrollIntoView);
11025 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11026 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11027 * @param {Number} index The zero-based index of the list item to select
11028 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11029 * selected item if it is not currently in view (defaults to true)
11031 select : function(index, scrollIntoView){
11032 this.selectedIndex = index;
11033 this.view.select(index);
11034 if(scrollIntoView !== false){
11035 var el = this.view.getNode(index);
11037 //this.innerList.scrollChildIntoView(el, false);
11044 selectNext : function(){
11045 var ct = this.store.getCount();
11047 if(this.selectedIndex == -1){
11049 }else if(this.selectedIndex < ct-1){
11050 this.select(this.selectedIndex+1);
11056 selectPrev : function(){
11057 var ct = this.store.getCount();
11059 if(this.selectedIndex == -1){
11061 }else if(this.selectedIndex != 0){
11062 this.select(this.selectedIndex-1);
11068 onKeyUp : function(e){
11069 if(this.editable !== false && !e.isSpecialKey()){
11070 this.lastKey = e.getKey();
11071 this.dqTask.delay(this.queryDelay);
11076 validateBlur : function(){
11077 return !this.list || !this.list.isVisible();
11081 initQuery : function(){
11082 this.doQuery(this.getRawValue());
11086 doForce : function(){
11087 if(this.inputEl().dom.value.length > 0){
11088 this.inputEl().dom.value =
11089 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11095 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11096 * query allowing the query action to be canceled if needed.
11097 * @param {String} query The SQL query to execute
11098 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11099 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11100 * saved in the current store (defaults to false)
11102 doQuery : function(q, forceAll){
11104 if(q === undefined || q === null){
11109 forceAll: forceAll,
11113 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11118 forceAll = qe.forceAll;
11119 if(forceAll === true || (q.length >= this.minChars)){
11121 this.hasQuery = true;
11123 if(this.lastQuery != q || this.alwaysQuery){
11124 this.lastQuery = q;
11125 if(this.mode == 'local'){
11126 this.selectedIndex = -1;
11128 this.store.clearFilter();
11130 this.store.filter(this.displayField, q);
11134 this.store.baseParams[this.queryParam] = q;
11136 var options = {params : this.getParams(q)};
11139 options.add = true;
11140 options.params.start = this.page * this.pageSize;
11143 this.store.load(options);
11145 * this code will make the page width larger, at the beginning, the list not align correctly,
11146 * we should expand the list on onLoad
11147 * so command out it
11152 this.selectedIndex = -1;
11157 this.loadNext = false;
11161 getParams : function(q){
11163 //p[this.queryParam] = q;
11167 p.limit = this.pageSize;
11173 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11175 collapse : function(){
11176 if(!this.isExpanded()){
11184 this.cancelBtn.hide();
11185 this.trigger.show();
11188 Roo.get(document).un('mousedown', this.collapseIf, this);
11189 Roo.get(document).un('mousewheel', this.collapseIf, this);
11190 if (!this.editable) {
11191 Roo.get(document).un('keydown', this.listKeyPress, this);
11193 this.fireEvent('collapse', this);
11197 collapseIf : function(e){
11198 var in_combo = e.within(this.el);
11199 var in_list = e.within(this.list);
11201 if (in_combo || in_list) {
11202 //e.stopPropagation();
11207 this.onTickableFooterButtonClick(e, false, false);
11215 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11217 expand : function(){
11219 if(this.isExpanded() || !this.hasFocus){
11223 this.list.alignTo(this.inputEl(), this.listAlign);
11228 this.tickItems = Roo.apply([], this.item);
11231 this.cancelBtn.show();
11232 this.trigger.hide();
11236 Roo.get(document).on('mousedown', this.collapseIf, this);
11237 Roo.get(document).on('mousewheel', this.collapseIf, this);
11238 if (!this.editable) {
11239 Roo.get(document).on('keydown', this.listKeyPress, this);
11242 this.fireEvent('expand', this);
11246 // Implements the default empty TriggerField.onTriggerClick function
11247 onTriggerClick : function()
11249 Roo.log('trigger click');
11256 this.onTickableTriggerClick();
11261 this.loadNext = false;
11263 if(this.isExpanded()){
11265 if (!this.blockFocus) {
11266 this.inputEl().focus();
11270 this.hasFocus = true;
11271 if(this.triggerAction == 'all') {
11272 this.doQuery(this.allQuery, true);
11274 this.doQuery(this.getRawValue());
11276 if (!this.blockFocus) {
11277 this.inputEl().focus();
11282 onTickableTriggerClick : function()
11285 this.loadNext = false;
11286 this.hasFocus = true;
11288 if(this.triggerAction == 'all') {
11289 this.doQuery(this.allQuery, true);
11291 this.doQuery(this.getRawValue());
11295 listKeyPress : function(e)
11297 //Roo.log('listkeypress');
11298 // scroll to first matching element based on key pres..
11299 if (e.isSpecialKey()) {
11302 var k = String.fromCharCode(e.getKey()).toUpperCase();
11305 var csel = this.view.getSelectedNodes();
11306 var cselitem = false;
11308 var ix = this.view.indexOf(csel[0]);
11309 cselitem = this.store.getAt(ix);
11310 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11316 this.store.each(function(v) {
11318 // start at existing selection.
11319 if (cselitem.id == v.id) {
11325 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11326 match = this.store.indexOf(v);
11332 if (match === false) {
11333 return true; // no more action?
11336 this.view.select(match);
11337 var sn = Roo.get(this.view.getSelectedNodes()[0])
11338 //sn.scrollIntoView(sn.dom.parentNode, false);
11341 onViewScroll : function(e, t){
11343 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
11347 this.hasQuery = true;
11349 this.loading = this.list.select('.loading', true).first();
11351 if(this.loading === null){
11352 this.list.createChild({
11354 cls: 'loading select2-more-results select2-active',
11355 html: 'Loading more results...'
11358 this.loading = this.list.select('.loading', true).first();
11360 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11362 this.loading.hide();
11365 this.loading.show();
11370 this.loadNext = true;
11372 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11377 addItem : function(o)
11379 var dv = ''; // display value
11381 if (this.displayField) {
11382 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11384 // this is an error condition!!!
11385 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11392 var choice = this.choices.createChild({
11394 cls: 'select2-search-choice',
11403 cls: 'select2-search-choice-close',
11408 }, this.searchField);
11410 var close = choice.select('a.select2-search-choice-close', true).first()
11412 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11420 this.inputEl().dom.value = '';
11424 onRemoveItem : function(e, _self, o)
11426 e.preventDefault();
11427 var index = this.item.indexOf(o.data) * 1;
11430 Roo.log('not this item?!');
11434 this.item.splice(index, 1);
11439 this.fireEvent('remove', this, e);
11443 syncValue : function()
11445 if(!this.item.length){
11452 Roo.each(this.item, function(i){
11453 if(_this.valueField){
11454 value.push(i[_this.valueField]);
11461 this.value = value.join(',');
11463 if(this.hiddenField){
11464 this.hiddenField.dom.value = this.value;
11468 clearItem : function()
11470 if(!this.multiple){
11476 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11483 inputEl: function ()
11486 return this.searchField;
11488 return this.el.select('input.form-control',true).first();
11492 onTickableFooterButtonClick : function(e, btn, el)
11494 e.preventDefault();
11496 if(btn && btn.name == 'cancel'){
11497 this.tickItems = Roo.apply([], this.item);
11506 Roo.each(this.tickItems, function(o){
11517 * @cfg {Boolean} grow
11521 * @cfg {Number} growMin
11525 * @cfg {Number} growMax
11535 * Ext JS Library 1.1.1
11536 * Copyright(c) 2006-2007, Ext JS, LLC.
11538 * Originally Released Under LGPL - original licence link has changed is not relivant.
11541 * <script type="text/javascript">
11546 * @extends Roo.util.Observable
11547 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11548 * This class also supports single and multi selection modes. <br>
11549 * Create a data model bound view:
11551 var store = new Roo.data.Store(...);
11553 var view = new Roo.View({
11555 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11557 singleSelect: true,
11558 selectedClass: "ydataview-selected",
11562 // listen for node click?
11563 view.on("click", function(vw, index, node, e){
11564 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
11568 dataModel.load("foobar.xml");
11570 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
11572 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
11573 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
11575 * Note: old style constructor is still suported (container, template, config)
11578 * Create a new View
11579 * @param {Object} config The config object
11582 Roo.View = function(config, depreciated_tpl, depreciated_config){
11584 this.parent = false;
11586 if (typeof(depreciated_tpl) == 'undefined') {
11587 // new way.. - universal constructor.
11588 Roo.apply(this, config);
11589 this.el = Roo.get(this.el);
11592 this.el = Roo.get(config);
11593 this.tpl = depreciated_tpl;
11594 Roo.apply(this, depreciated_config);
11596 this.wrapEl = this.el.wrap().wrap();
11597 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
11600 if(typeof(this.tpl) == "string"){
11601 this.tpl = new Roo.Template(this.tpl);
11603 // support xtype ctors..
11604 this.tpl = new Roo.factory(this.tpl, Roo);
11608 this.tpl.compile();
11613 * @event beforeclick
11614 * Fires before a click is processed. Returns false to cancel the default action.
11615 * @param {Roo.View} this
11616 * @param {Number} index The index of the target node
11617 * @param {HTMLElement} node The target node
11618 * @param {Roo.EventObject} e The raw event object
11620 "beforeclick" : true,
11623 * Fires when a template node is clicked.
11624 * @param {Roo.View} this
11625 * @param {Number} index The index of the target node
11626 * @param {HTMLElement} node The target node
11627 * @param {Roo.EventObject} e The raw event object
11632 * Fires when a template node is double clicked.
11633 * @param {Roo.View} this
11634 * @param {Number} index The index of the target node
11635 * @param {HTMLElement} node The target node
11636 * @param {Roo.EventObject} e The raw event object
11640 * @event contextmenu
11641 * Fires when a template node is right clicked.
11642 * @param {Roo.View} this
11643 * @param {Number} index The index of the target node
11644 * @param {HTMLElement} node The target node
11645 * @param {Roo.EventObject} e The raw event object
11647 "contextmenu" : true,
11649 * @event selectionchange
11650 * Fires when the selected nodes change.
11651 * @param {Roo.View} this
11652 * @param {Array} selections Array of the selected nodes
11654 "selectionchange" : true,
11657 * @event beforeselect
11658 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
11659 * @param {Roo.View} this
11660 * @param {HTMLElement} node The node to be selected
11661 * @param {Array} selections Array of currently selected nodes
11663 "beforeselect" : true,
11665 * @event preparedata
11666 * Fires on every row to render, to allow you to change the data.
11667 * @param {Roo.View} this
11668 * @param {Object} data to be rendered (change this)
11670 "preparedata" : true
11678 "click": this.onClick,
11679 "dblclick": this.onDblClick,
11680 "contextmenu": this.onContextMenu,
11684 this.selections = [];
11686 this.cmp = new Roo.CompositeElementLite([]);
11688 this.store = Roo.factory(this.store, Roo.data);
11689 this.setStore(this.store, true);
11692 if ( this.footer && this.footer.xtype) {
11694 var fctr = this.wrapEl.appendChild(document.createElement("div"));
11696 this.footer.dataSource = this.store
11697 this.footer.container = fctr;
11698 this.footer = Roo.factory(this.footer, Roo);
11699 fctr.insertFirst(this.el);
11701 // this is a bit insane - as the paging toolbar seems to detach the el..
11702 // dom.parentNode.parentNode.parentNode
11703 // they get detached?
11707 Roo.View.superclass.constructor.call(this);
11712 Roo.extend(Roo.View, Roo.util.Observable, {
11715 * @cfg {Roo.data.Store} store Data store to load data from.
11720 * @cfg {String|Roo.Element} el The container element.
11725 * @cfg {String|Roo.Template} tpl The template used by this View
11729 * @cfg {String} dataName the named area of the template to use as the data area
11730 * Works with domtemplates roo-name="name"
11734 * @cfg {String} selectedClass The css class to add to selected nodes
11736 selectedClass : "x-view-selected",
11738 * @cfg {String} emptyText The empty text to show when nothing is loaded.
11743 * @cfg {String} text to display on mask (default Loading)
11747 * @cfg {Boolean} multiSelect Allow multiple selection
11749 multiSelect : false,
11751 * @cfg {Boolean} singleSelect Allow single selection
11753 singleSelect: false,
11756 * @cfg {Boolean} toggleSelect - selecting
11758 toggleSelect : false,
11761 * @cfg {Boolean} tickable - selecting
11766 * Returns the element this view is bound to.
11767 * @return {Roo.Element}
11769 getEl : function(){
11770 return this.wrapEl;
11776 * Refreshes the view. - called by datachanged on the store. - do not call directly.
11778 refresh : function(){
11779 Roo.log('refresh');
11782 // if we are using something like 'domtemplate', then
11783 // the what gets used is:
11784 // t.applySubtemplate(NAME, data, wrapping data..)
11785 // the outer template then get' applied with
11786 // the store 'extra data'
11787 // and the body get's added to the
11788 // roo-name="data" node?
11789 // <span class='roo-tpl-{name}'></span> ?????
11793 this.clearSelections();
11794 this.el.update("");
11796 var records = this.store.getRange();
11797 if(records.length < 1) {
11799 // is this valid?? = should it render a template??
11801 this.el.update(this.emptyText);
11805 if (this.dataName) {
11806 this.el.update(t.apply(this.store.meta)); //????
11807 el = this.el.child('.roo-tpl-' + this.dataName);
11810 for(var i = 0, len = records.length; i < len; i++){
11811 var data = this.prepareData(records[i].data, i, records[i]);
11812 this.fireEvent("preparedata", this, data, i, records[i]);
11814 var d = Roo.apply({}, data);
11817 Roo.apply(d, {'roo-id' : Roo.id()});
11821 Roo.each(this.parent.item, function(item){
11822 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
11825 Roo.apply(d, {'roo-data-checked' : 'checked'});
11829 html[html.length] = Roo.util.Format.trim(
11831 t.applySubtemplate(this.dataName, d, this.store.meta) :
11838 el.update(html.join(""));
11839 this.nodes = el.dom.childNodes;
11840 this.updateIndexes(0);
11845 * Function to override to reformat the data that is sent to
11846 * the template for each node.
11847 * DEPRICATED - use the preparedata event handler.
11848 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
11849 * a JSON object for an UpdateManager bound view).
11851 prepareData : function(data, index, record)
11853 this.fireEvent("preparedata", this, data, index, record);
11857 onUpdate : function(ds, record){
11858 Roo.log('on update');
11859 this.clearSelections();
11860 var index = this.store.indexOf(record);
11861 var n = this.nodes[index];
11862 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
11863 n.parentNode.removeChild(n);
11864 this.updateIndexes(index, index);
11870 onAdd : function(ds, records, index)
11872 Roo.log(['on Add', ds, records, index] );
11873 this.clearSelections();
11874 if(this.nodes.length == 0){
11878 var n = this.nodes[index];
11879 for(var i = 0, len = records.length; i < len; i++){
11880 var d = this.prepareData(records[i].data, i, records[i]);
11882 this.tpl.insertBefore(n, d);
11885 this.tpl.append(this.el, d);
11888 this.updateIndexes(index);
11891 onRemove : function(ds, record, index){
11892 Roo.log('onRemove');
11893 this.clearSelections();
11894 var el = this.dataName ?
11895 this.el.child('.roo-tpl-' + this.dataName) :
11898 el.dom.removeChild(this.nodes[index]);
11899 this.updateIndexes(index);
11903 * Refresh an individual node.
11904 * @param {Number} index
11906 refreshNode : function(index){
11907 this.onUpdate(this.store, this.store.getAt(index));
11910 updateIndexes : function(startIndex, endIndex){
11911 var ns = this.nodes;
11912 startIndex = startIndex || 0;
11913 endIndex = endIndex || ns.length - 1;
11914 for(var i = startIndex; i <= endIndex; i++){
11915 ns[i].nodeIndex = i;
11920 * Changes the data store this view uses and refresh the view.
11921 * @param {Store} store
11923 setStore : function(store, initial){
11924 if(!initial && this.store){
11925 this.store.un("datachanged", this.refresh);
11926 this.store.un("add", this.onAdd);
11927 this.store.un("remove", this.onRemove);
11928 this.store.un("update", this.onUpdate);
11929 this.store.un("clear", this.refresh);
11930 this.store.un("beforeload", this.onBeforeLoad);
11931 this.store.un("load", this.onLoad);
11932 this.store.un("loadexception", this.onLoad);
11936 store.on("datachanged", this.refresh, this);
11937 store.on("add", this.onAdd, this);
11938 store.on("remove", this.onRemove, this);
11939 store.on("update", this.onUpdate, this);
11940 store.on("clear", this.refresh, this);
11941 store.on("beforeload", this.onBeforeLoad, this);
11942 store.on("load", this.onLoad, this);
11943 store.on("loadexception", this.onLoad, this);
11951 * onbeforeLoad - masks the loading area.
11954 onBeforeLoad : function(store,opts)
11956 Roo.log('onBeforeLoad');
11958 this.el.update("");
11960 this.el.mask(this.mask ? this.mask : "Loading" );
11962 onLoad : function ()
11969 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
11970 * @param {HTMLElement} node
11971 * @return {HTMLElement} The template node
11973 findItemFromChild : function(node){
11974 var el = this.dataName ?
11975 this.el.child('.roo-tpl-' + this.dataName,true) :
11978 if(!node || node.parentNode == el){
11981 var p = node.parentNode;
11982 while(p && p != el){
11983 if(p.parentNode == el){
11992 onClick : function(e){
11993 var item = this.findItemFromChild(e.getTarget());
11995 var index = this.indexOf(item);
11996 if(this.onItemClick(item, index, e) !== false){
11997 this.fireEvent("click", this, index, item, e);
12000 this.clearSelections();
12005 onContextMenu : function(e){
12006 var item = this.findItemFromChild(e.getTarget());
12008 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12013 onDblClick : function(e){
12014 var item = this.findItemFromChild(e.getTarget());
12016 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12020 onItemClick : function(item, index, e)
12022 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12025 if (this.toggleSelect) {
12026 var m = this.isSelected(item) ? 'unselect' : 'select';
12029 _t[m](item, true, false);
12032 if(this.multiSelect || this.singleSelect){
12033 if(this.multiSelect && e.shiftKey && this.lastSelection){
12034 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12036 this.select(item, this.multiSelect && e.ctrlKey);
12037 this.lastSelection = item;
12040 if(!this.tickable){
12041 e.preventDefault();
12049 * Get the number of selected nodes.
12052 getSelectionCount : function(){
12053 return this.selections.length;
12057 * Get the currently selected nodes.
12058 * @return {Array} An array of HTMLElements
12060 getSelectedNodes : function(){
12061 return this.selections;
12065 * Get the indexes of the selected nodes.
12068 getSelectedIndexes : function(){
12069 var indexes = [], s = this.selections;
12070 for(var i = 0, len = s.length; i < len; i++){
12071 indexes.push(s[i].nodeIndex);
12077 * Clear all selections
12078 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12080 clearSelections : function(suppressEvent){
12081 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12082 this.cmp.elements = this.selections;
12083 this.cmp.removeClass(this.selectedClass);
12084 this.selections = [];
12085 if(!suppressEvent){
12086 this.fireEvent("selectionchange", this, this.selections);
12092 * Returns true if the passed node is selected
12093 * @param {HTMLElement/Number} node The node or node index
12094 * @return {Boolean}
12096 isSelected : function(node){
12097 var s = this.selections;
12101 node = this.getNode(node);
12102 return s.indexOf(node) !== -1;
12107 * @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
12108 * @param {Boolean} keepExisting (optional) true to keep existing selections
12109 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12111 select : function(nodeInfo, keepExisting, suppressEvent){
12112 if(nodeInfo instanceof Array){
12114 this.clearSelections(true);
12116 for(var i = 0, len = nodeInfo.length; i < len; i++){
12117 this.select(nodeInfo[i], true, true);
12121 var node = this.getNode(nodeInfo);
12122 if(!node || this.isSelected(node)){
12123 return; // already selected.
12126 this.clearSelections(true);
12128 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12129 Roo.fly(node).addClass(this.selectedClass);
12130 this.selections.push(node);
12131 if(!suppressEvent){
12132 this.fireEvent("selectionchange", this, this.selections);
12140 * @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
12141 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12142 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12144 unselect : function(nodeInfo, keepExisting, suppressEvent)
12146 if(nodeInfo instanceof Array){
12147 Roo.each(this.selections, function(s) {
12148 this.unselect(s, nodeInfo);
12152 var node = this.getNode(nodeInfo);
12153 if(!node || !this.isSelected(node)){
12154 Roo.log("not selected");
12155 return; // not selected.
12159 Roo.each(this.selections, function(s) {
12161 Roo.fly(node).removeClass(this.selectedClass);
12168 this.selections= ns;
12169 this.fireEvent("selectionchange", this, this.selections);
12173 * Gets a template node.
12174 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12175 * @return {HTMLElement} The node or null if it wasn't found
12177 getNode : function(nodeInfo){
12178 if(typeof nodeInfo == "string"){
12179 return document.getElementById(nodeInfo);
12180 }else if(typeof nodeInfo == "number"){
12181 return this.nodes[nodeInfo];
12187 * Gets a range template nodes.
12188 * @param {Number} startIndex
12189 * @param {Number} endIndex
12190 * @return {Array} An array of nodes
12192 getNodes : function(start, end){
12193 var ns = this.nodes;
12194 start = start || 0;
12195 end = typeof end == "undefined" ? ns.length - 1 : end;
12198 for(var i = start; i <= end; i++){
12202 for(var i = start; i >= end; i--){
12210 * Finds the index of the passed node
12211 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12212 * @return {Number} The index of the node or -1
12214 indexOf : function(node){
12215 node = this.getNode(node);
12216 if(typeof node.nodeIndex == "number"){
12217 return node.nodeIndex;
12219 var ns = this.nodes;
12220 for(var i = 0, len = ns.length; i < len; i++){
12231 * based on jquery fullcalendar
12235 Roo.bootstrap = Roo.bootstrap || {};
12237 * @class Roo.bootstrap.Calendar
12238 * @extends Roo.bootstrap.Component
12239 * Bootstrap Calendar class
12240 * @cfg {Boolean} loadMask (true|false) default false
12241 * @cfg {Object} header generate the user specific header of the calendar, default false
12244 * Create a new Container
12245 * @param {Object} config The config object
12250 Roo.bootstrap.Calendar = function(config){
12251 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12255 * Fires when a date is selected
12256 * @param {DatePicker} this
12257 * @param {Date} date The selected date
12261 * @event monthchange
12262 * Fires when the displayed month changes
12263 * @param {DatePicker} this
12264 * @param {Date} date The selected month
12266 'monthchange': true,
12268 * @event evententer
12269 * Fires when mouse over an event
12270 * @param {Calendar} this
12271 * @param {event} Event
12273 'evententer': true,
12275 * @event eventleave
12276 * Fires when the mouse leaves an
12277 * @param {Calendar} this
12280 'eventleave': true,
12282 * @event eventclick
12283 * Fires when the mouse click an
12284 * @param {Calendar} this
12293 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12296 * @cfg {Number} startDay
12297 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12305 getAutoCreate : function(){
12308 var fc_button = function(name, corner, style, content ) {
12309 return Roo.apply({},{
12311 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12313 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12316 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12327 style : 'width:100%',
12334 cls : 'fc-header-left',
12336 fc_button('prev', 'left', 'arrow', '‹' ),
12337 fc_button('next', 'right', 'arrow', '›' ),
12338 { tag: 'span', cls: 'fc-header-space' },
12339 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12347 cls : 'fc-header-center',
12351 cls: 'fc-header-title',
12354 html : 'month / year'
12362 cls : 'fc-header-right',
12364 /* fc_button('month', 'left', '', 'month' ),
12365 fc_button('week', '', '', 'week' ),
12366 fc_button('day', 'right', '', 'day' )
12378 header = this.header;
12381 var cal_heads = function() {
12383 // fixme - handle this.
12385 for (var i =0; i < Date.dayNames.length; i++) {
12386 var d = Date.dayNames[i];
12389 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12390 html : d.substring(0,3)
12394 ret[0].cls += ' fc-first';
12395 ret[6].cls += ' fc-last';
12398 var cal_cell = function(n) {
12401 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12406 cls: 'fc-day-number',
12410 cls: 'fc-day-content',
12414 style: 'position: relative;' // height: 17px;
12426 var cal_rows = function() {
12429 for (var r = 0; r < 6; r++) {
12436 for (var i =0; i < Date.dayNames.length; i++) {
12437 var d = Date.dayNames[i];
12438 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12441 row.cn[0].cls+=' fc-first';
12442 row.cn[0].cn[0].style = 'min-height:90px';
12443 row.cn[6].cls+=' fc-last';
12447 ret[0].cls += ' fc-first';
12448 ret[4].cls += ' fc-prev-last';
12449 ret[5].cls += ' fc-last';
12456 cls: 'fc-border-separate',
12457 style : 'width:100%',
12465 cls : 'fc-first fc-last',
12483 cls : 'fc-content',
12484 style : "position: relative;",
12487 cls : 'fc-view fc-view-month fc-grid',
12488 style : 'position: relative',
12489 unselectable : 'on',
12492 cls : 'fc-event-container',
12493 style : 'position:absolute;z-index:8;top:0;left:0;'
12511 initEvents : function()
12514 throw "can not find store for calendar";
12520 style: "text-align:center",
12524 style: "background-color:white;width:50%;margin:250 auto",
12528 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12539 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12541 var size = this.el.select('.fc-content', true).first().getSize();
12542 this.maskEl.setSize(size.width, size.height);
12543 this.maskEl.enableDisplayMode("block");
12544 if(!this.loadMask){
12545 this.maskEl.hide();
12548 this.store = Roo.factory(this.store, Roo.data);
12549 this.store.on('load', this.onLoad, this);
12550 this.store.on('beforeload', this.onBeforeLoad, this);
12554 this.cells = this.el.select('.fc-day',true);
12555 //Roo.log(this.cells);
12556 this.textNodes = this.el.query('.fc-day-number');
12557 this.cells.addClassOnOver('fc-state-hover');
12559 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12560 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12561 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12562 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12564 this.on('monthchange', this.onMonthChange, this);
12566 this.update(new Date().clearTime());
12569 resize : function() {
12570 var sz = this.el.getSize();
12572 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
12573 this.el.select('.fc-day-content div',true).setHeight(34);
12578 showPrevMonth : function(e){
12579 this.update(this.activeDate.add("mo", -1));
12581 showToday : function(e){
12582 this.update(new Date().clearTime());
12585 showNextMonth : function(e){
12586 this.update(this.activeDate.add("mo", 1));
12590 showPrevYear : function(){
12591 this.update(this.activeDate.add("y", -1));
12595 showNextYear : function(){
12596 this.update(this.activeDate.add("y", 1));
12601 update : function(date)
12603 var vd = this.activeDate;
12604 this.activeDate = date;
12605 // if(vd && this.el){
12606 // var t = date.getTime();
12607 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
12608 // Roo.log('using add remove');
12610 // this.fireEvent('monthchange', this, date);
12612 // this.cells.removeClass("fc-state-highlight");
12613 // this.cells.each(function(c){
12614 // if(c.dateValue == t){
12615 // c.addClass("fc-state-highlight");
12616 // setTimeout(function(){
12617 // try{c.dom.firstChild.focus();}catch(e){}
12627 var days = date.getDaysInMonth();
12629 var firstOfMonth = date.getFirstDateOfMonth();
12630 var startingPos = firstOfMonth.getDay()-this.startDay;
12632 if(startingPos < this.startDay){
12636 var pm = date.add(Date.MONTH, -1);
12637 var prevStart = pm.getDaysInMonth()-startingPos;
12639 this.cells = this.el.select('.fc-day',true);
12640 this.textNodes = this.el.query('.fc-day-number');
12641 this.cells.addClassOnOver('fc-state-hover');
12643 var cells = this.cells.elements;
12644 var textEls = this.textNodes;
12646 Roo.each(cells, function(cell){
12647 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
12650 days += startingPos;
12652 // convert everything to numbers so it's fast
12653 var day = 86400000;
12654 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
12657 //Roo.log(prevStart);
12659 var today = new Date().clearTime().getTime();
12660 var sel = date.clearTime().getTime();
12661 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
12662 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
12663 var ddMatch = this.disabledDatesRE;
12664 var ddText = this.disabledDatesText;
12665 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
12666 var ddaysText = this.disabledDaysText;
12667 var format = this.format;
12669 var setCellClass = function(cal, cell){
12673 //Roo.log('set Cell Class');
12675 var t = d.getTime();
12679 cell.dateValue = t;
12681 cell.className += " fc-today";
12682 cell.className += " fc-state-highlight";
12683 cell.title = cal.todayText;
12686 // disable highlight in other month..
12687 //cell.className += " fc-state-highlight";
12692 cell.className = " fc-state-disabled";
12693 cell.title = cal.minText;
12697 cell.className = " fc-state-disabled";
12698 cell.title = cal.maxText;
12702 if(ddays.indexOf(d.getDay()) != -1){
12703 cell.title = ddaysText;
12704 cell.className = " fc-state-disabled";
12707 if(ddMatch && format){
12708 var fvalue = d.dateFormat(format);
12709 if(ddMatch.test(fvalue)){
12710 cell.title = ddText.replace("%0", fvalue);
12711 cell.className = " fc-state-disabled";
12715 if (!cell.initialClassName) {
12716 cell.initialClassName = cell.dom.className;
12719 cell.dom.className = cell.initialClassName + ' ' + cell.className;
12724 for(; i < startingPos; i++) {
12725 textEls[i].innerHTML = (++prevStart);
12726 d.setDate(d.getDate()+1);
12728 cells[i].className = "fc-past fc-other-month";
12729 setCellClass(this, cells[i]);
12734 for(; i < days; i++){
12735 intDay = i - startingPos + 1;
12736 textEls[i].innerHTML = (intDay);
12737 d.setDate(d.getDate()+1);
12739 cells[i].className = ''; // "x-date-active";
12740 setCellClass(this, cells[i]);
12744 for(; i < 42; i++) {
12745 textEls[i].innerHTML = (++extraDays);
12746 d.setDate(d.getDate()+1);
12748 cells[i].className = "fc-future fc-other-month";
12749 setCellClass(this, cells[i]);
12752 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
12754 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
12756 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
12757 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
12759 if(totalRows != 6){
12760 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
12761 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
12764 this.fireEvent('monthchange', this, date);
12768 if(!this.internalRender){
12769 var main = this.el.dom.firstChild;
12770 var w = main.offsetWidth;
12771 this.el.setWidth(w + this.el.getBorderWidth("lr"));
12772 Roo.fly(main).setWidth(w);
12773 this.internalRender = true;
12774 // opera does not respect the auto grow header center column
12775 // then, after it gets a width opera refuses to recalculate
12776 // without a second pass
12777 if(Roo.isOpera && !this.secondPass){
12778 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
12779 this.secondPass = true;
12780 this.update.defer(10, this, [date]);
12787 findCell : function(dt) {
12788 dt = dt.clearTime().getTime();
12790 this.cells.each(function(c){
12791 //Roo.log("check " +c.dateValue + '?=' + dt);
12792 if(c.dateValue == dt){
12802 findCells : function(ev) {
12803 var s = ev.start.clone().clearTime().getTime();
12805 var e= ev.end.clone().clearTime().getTime();
12808 this.cells.each(function(c){
12809 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
12811 if(c.dateValue > e){
12814 if(c.dateValue < s){
12823 // findBestRow: function(cells)
12827 // for (var i =0 ; i < cells.length;i++) {
12828 // ret = Math.max(cells[i].rows || 0,ret);
12835 addItem : function(ev)
12837 // look for vertical location slot in
12838 var cells = this.findCells(ev);
12840 // ev.row = this.findBestRow(cells);
12842 // work out the location.
12846 for(var i =0; i < cells.length; i++) {
12848 cells[i].row = cells[0].row;
12851 cells[i].row = cells[i].row + 1;
12861 if (crow.start.getY() == cells[i].getY()) {
12863 crow.end = cells[i];
12880 cells[0].events.push(ev);
12882 this.calevents.push(ev);
12885 clearEvents: function() {
12887 if(!this.calevents){
12891 Roo.each(this.cells.elements, function(c){
12897 Roo.each(this.calevents, function(e) {
12898 Roo.each(e.els, function(el) {
12899 el.un('mouseenter' ,this.onEventEnter, this);
12900 el.un('mouseleave' ,this.onEventLeave, this);
12905 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
12911 renderEvents: function()
12915 this.cells.each(function(c) {
12924 if(c.row != c.events.length){
12925 r = 4 - (4 - (c.row - c.events.length));
12928 c.events = ev.slice(0, r);
12929 c.more = ev.slice(r);
12931 if(c.more.length && c.more.length == 1){
12932 c.events.push(c.more.pop());
12935 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
12939 this.cells.each(function(c) {
12941 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
12944 for (var e = 0; e < c.events.length; e++){
12945 var ev = c.events[e];
12946 var rows = ev.rows;
12948 for(var i = 0; i < rows.length; i++) {
12950 // how many rows should it span..
12953 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
12954 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
12956 unselectable : "on",
12959 cls: 'fc-event-inner',
12963 // cls: 'fc-event-time',
12964 // html : cells.length > 1 ? '' : ev.time
12968 cls: 'fc-event-title',
12969 html : String.format('{0}', ev.title)
12976 cls: 'ui-resizable-handle ui-resizable-e',
12977 html : '  '
12984 cfg.cls += ' fc-event-start';
12986 if ((i+1) == rows.length) {
12987 cfg.cls += ' fc-event-end';
12990 var ctr = _this.el.select('.fc-event-container',true).first();
12991 var cg = ctr.createChild(cfg);
12993 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
12994 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
12996 var r = (c.more.length) ? 1 : 0;
12997 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
12998 cg.setWidth(ebox.right - sbox.x -2);
13000 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13001 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13002 cg.on('click', _this.onEventClick, _this, ev);
13013 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13014 style : 'position: absolute',
13015 unselectable : "on",
13018 cls: 'fc-event-inner',
13022 cls: 'fc-event-title',
13030 cls: 'ui-resizable-handle ui-resizable-e',
13031 html : '  '
13037 var ctr = _this.el.select('.fc-event-container',true).first();
13038 var cg = ctr.createChild(cfg);
13040 var sbox = c.select('.fc-day-content',true).first().getBox();
13041 var ebox = c.select('.fc-day-content',true).first().getBox();
13043 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13044 cg.setWidth(ebox.right - sbox.x -2);
13046 cg.on('click', _this.onMoreEventClick, _this, c.more);
13056 onEventEnter: function (e, el,event,d) {
13057 this.fireEvent('evententer', this, el, event);
13060 onEventLeave: function (e, el,event,d) {
13061 this.fireEvent('eventleave', this, el, event);
13064 onEventClick: function (e, el,event,d) {
13065 this.fireEvent('eventclick', this, el, event);
13068 onMonthChange: function () {
13072 onMoreEventClick: function(e, el, more)
13076 this.calpopover.placement = 'right';
13077 this.calpopover.setTitle('More');
13079 this.calpopover.setContent('');
13081 var ctr = this.calpopover.el.select('.popover-content', true).first();
13083 Roo.each(more, function(m){
13085 cls : 'fc-event-hori fc-event-draggable',
13088 var cg = ctr.createChild(cfg);
13090 cg.on('click', _this.onEventClick, _this, m);
13093 this.calpopover.show(el);
13098 onLoad: function ()
13100 this.calevents = [];
13103 if(this.store.getCount() > 0){
13104 this.store.data.each(function(d){
13107 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13108 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13109 time : d.data.start_time,
13110 title : d.data.title,
13111 description : d.data.description,
13112 venue : d.data.venue
13117 this.renderEvents();
13119 if(this.calevents.length && this.loadMask){
13120 this.maskEl.hide();
13124 onBeforeLoad: function()
13126 this.clearEvents();
13128 this.maskEl.show();
13142 * @class Roo.bootstrap.Popover
13143 * @extends Roo.bootstrap.Component
13144 * Bootstrap Popover class
13145 * @cfg {String} html contents of the popover (or false to use children..)
13146 * @cfg {String} title of popover (or false to hide)
13147 * @cfg {String} placement how it is placed
13148 * @cfg {String} trigger click || hover (or false to trigger manually)
13149 * @cfg {String} over what (parent or false to trigger manually.)
13152 * Create a new Popover
13153 * @param {Object} config The config object
13156 Roo.bootstrap.Popover = function(config){
13157 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13160 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13162 title: 'Fill in a title',
13165 placement : 'right',
13166 trigger : 'hover', // hover
13170 can_build_overlaid : false,
13172 getChildContainer : function()
13174 return this.el.select('.popover-content',true).first();
13177 getAutoCreate : function(){
13178 Roo.log('make popover?');
13180 cls : 'popover roo-dynamic',
13181 style: 'display:block',
13187 cls : 'popover-inner',
13191 cls: 'popover-title',
13195 cls : 'popover-content',
13206 setTitle: function(str)
13208 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13210 setContent: function(str)
13212 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13214 // as it get's added to the bottom of the page.
13215 onRender : function(ct, position)
13217 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13219 var cfg = Roo.apply({}, this.getAutoCreate());
13223 cfg.cls += ' ' + this.cls;
13226 cfg.style = this.style;
13228 Roo.log("adding to ")
13229 this.el = Roo.get(document.body).createChild(cfg, position);
13235 initEvents : function()
13237 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13238 this.el.enableDisplayMode('block');
13240 if (this.over === false) {
13243 if (this.triggers === false) {
13246 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13247 var triggers = this.trigger ? this.trigger.split(' ') : [];
13248 Roo.each(triggers, function(trigger) {
13250 if (trigger == 'click') {
13251 on_el.on('click', this.toggle, this);
13252 } else if (trigger != 'manual') {
13253 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13254 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13256 on_el.on(eventIn ,this.enter, this);
13257 on_el.on(eventOut, this.leave, this);
13268 toggle : function () {
13269 this.hoverState == 'in' ? this.leave() : this.enter();
13272 enter : function () {
13275 clearTimeout(this.timeout);
13277 this.hoverState = 'in'
13279 if (!this.delay || !this.delay.show) {
13284 this.timeout = setTimeout(function () {
13285 if (_t.hoverState == 'in') {
13288 }, this.delay.show)
13290 leave : function() {
13291 clearTimeout(this.timeout);
13293 this.hoverState = 'out'
13295 if (!this.delay || !this.delay.hide) {
13300 this.timeout = setTimeout(function () {
13301 if (_t.hoverState == 'out') {
13304 }, this.delay.hide)
13307 show : function (on_el)
13310 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13313 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13314 if (this.html !== false) {
13315 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13317 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13318 if (!this.title.length) {
13319 this.el.select('.popover-title',true).hide();
13322 var placement = typeof this.placement == 'function' ?
13323 this.placement.call(this, this.el, on_el) :
13326 var autoToken = /\s?auto?\s?/i;
13327 var autoPlace = autoToken.test(placement);
13329 placement = placement.replace(autoToken, '') || 'top';
13333 //this.el.setXY([0,0]);
13335 this.el.dom.style.display='block';
13336 this.el.addClass(placement);
13338 //this.el.appendTo(on_el);
13340 var p = this.getPosition();
13341 var box = this.el.getBox();
13346 var align = Roo.bootstrap.Popover.alignment[placement]
13347 this.el.alignTo(on_el, align[0],align[1]);
13348 //var arrow = this.el.select('.arrow',true).first();
13349 //arrow.set(align[2],
13351 this.el.addClass('in');
13352 this.hoverState = null;
13354 if (this.el.hasClass('fade')) {
13361 this.el.setXY([0,0]);
13362 this.el.removeClass('in');
13369 Roo.bootstrap.Popover.alignment = {
13370 'left' : ['r-l', [-10,0], 'right'],
13371 'right' : ['l-r', [10,0], 'left'],
13372 'bottom' : ['t-b', [0,10], 'top'],
13373 'top' : [ 'b-t', [0,-10], 'bottom']
13384 * @class Roo.bootstrap.Progress
13385 * @extends Roo.bootstrap.Component
13386 * Bootstrap Progress class
13387 * @cfg {Boolean} striped striped of the progress bar
13388 * @cfg {Boolean} active animated of the progress bar
13392 * Create a new Progress
13393 * @param {Object} config The config object
13396 Roo.bootstrap.Progress = function(config){
13397 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13400 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13405 getAutoCreate : function(){
13413 cfg.cls += ' progress-striped';
13417 cfg.cls += ' active';
13436 * @class Roo.bootstrap.ProgressBar
13437 * @extends Roo.bootstrap.Component
13438 * Bootstrap ProgressBar class
13439 * @cfg {Number} aria_valuenow aria-value now
13440 * @cfg {Number} aria_valuemin aria-value min
13441 * @cfg {Number} aria_valuemax aria-value max
13442 * @cfg {String} label label for the progress bar
13443 * @cfg {String} panel (success | info | warning | danger )
13444 * @cfg {String} role role of the progress bar
13445 * @cfg {String} sr_only text
13449 * Create a new ProgressBar
13450 * @param {Object} config The config object
13453 Roo.bootstrap.ProgressBar = function(config){
13454 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13457 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13461 aria_valuemax : 100,
13467 getAutoCreate : function()
13472 cls: 'progress-bar',
13473 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13485 cfg.role = this.role;
13488 if(this.aria_valuenow){
13489 cfg['aria-valuenow'] = this.aria_valuenow;
13492 if(this.aria_valuemin){
13493 cfg['aria-valuemin'] = this.aria_valuemin;
13496 if(this.aria_valuemax){
13497 cfg['aria-valuemax'] = this.aria_valuemax;
13500 if(this.label && !this.sr_only){
13501 cfg.html = this.label;
13505 cfg.cls += ' progress-bar-' + this.panel;
13511 update : function(aria_valuenow)
13513 this.aria_valuenow = aria_valuenow;
13515 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13530 * @class Roo.bootstrap.TabPanel
13531 * @extends Roo.bootstrap.Component
13532 * Bootstrap TabPanel class
13533 * @cfg {Boolean} active panel active
13534 * @cfg {String} html panel content
13535 * @cfg {String} tabId tab relate id
13536 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
13540 * Create a new TabPanel
13541 * @param {Object} config The config object
13544 Roo.bootstrap.TabPanel = function(config){
13545 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
13549 * Fires when the active status changes
13550 * @param {Roo.bootstrap.TabPanel} this
13551 * @param {Boolean} state the new state
13558 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
13565 getAutoCreate : function(){
13569 html: this.html || ''
13573 cfg.cls += ' active';
13577 cfg.tabId = this.tabId;
13582 onRender : function(ct, position)
13584 // Roo.log("Call onRender: " + this.xtype);
13586 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
13588 if (this.navId && this.tabId) {
13589 var item = Roo.bootstrap.NavGroup.get(this.navId).getNavItem(this.tabId);
13591 Roo.log("could not find navID:" + this.navId + ", tabId: " + this.tabId);
13593 item.on('changed', function(item, state) {
13594 this.setActive(state);
13600 setActive: function(state)
13602 Roo.log("panel - set active " + this.tabId + "=" + state);
13604 this.active = state;
13606 this.el.removeClass('active');
13608 } else if (!this.el.hasClass('active')) {
13609 this.el.addClass('active');
13611 this.fireEvent('changed', this, state);
13628 * @class Roo.bootstrap.DateField
13629 * @extends Roo.bootstrap.Input
13630 * Bootstrap DateField class
13631 * @cfg {Number} weekStart default 0
13632 * @cfg {Number} weekStart default 0
13633 * @cfg {Number} viewMode default empty, (months|years)
13634 * @cfg {Number} minViewMode default empty, (months|years)
13635 * @cfg {Number} startDate default -Infinity
13636 * @cfg {Number} endDate default Infinity
13637 * @cfg {Boolean} todayHighlight default false
13638 * @cfg {Boolean} todayBtn default false
13639 * @cfg {Boolean} calendarWeeks default false
13640 * @cfg {Object} daysOfWeekDisabled default empty
13642 * @cfg {Boolean} keyboardNavigation default true
13643 * @cfg {String} language default en
13646 * Create a new DateField
13647 * @param {Object} config The config object
13650 Roo.bootstrap.DateField = function(config){
13651 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
13655 * Fires when this field show.
13656 * @param {Roo.bootstrap.DateField} this
13657 * @param {Mixed} date The date value
13662 * Fires when this field hide.
13663 * @param {Roo.bootstrap.DateField} this
13664 * @param {Mixed} date The date value
13669 * Fires when select a date.
13670 * @param {Roo.bootstrap.DateField} this
13671 * @param {Mixed} date The date value
13677 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
13680 * @cfg {String} format
13681 * The default date format string which can be overriden for localization support. The format must be
13682 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
13686 * @cfg {String} altFormats
13687 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
13688 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
13690 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
13698 todayHighlight : false,
13704 keyboardNavigation: true,
13706 calendarWeeks: false,
13708 startDate: -Infinity,
13712 daysOfWeekDisabled: [],
13716 UTCDate: function()
13718 return new Date(Date.UTC.apply(Date, arguments));
13721 UTCToday: function()
13723 var today = new Date();
13724 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
13727 getDate: function() {
13728 var d = this.getUTCDate();
13729 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
13732 getUTCDate: function() {
13736 setDate: function(d) {
13737 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
13740 setUTCDate: function(d) {
13742 this.setValue(this.formatDate(this.date));
13745 onRender: function(ct, position)
13748 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
13750 this.language = this.language || 'en';
13751 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
13752 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
13754 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
13755 this.format = this.format || 'm/d/y';
13756 this.isInline = false;
13757 this.isInput = true;
13758 this.component = this.el.select('.add-on', true).first() || false;
13759 this.component = (this.component && this.component.length === 0) ? false : this.component;
13760 this.hasInput = this.component && this.inputEL().length;
13762 if (typeof(this.minViewMode === 'string')) {
13763 switch (this.minViewMode) {
13765 this.minViewMode = 1;
13768 this.minViewMode = 2;
13771 this.minViewMode = 0;
13776 if (typeof(this.viewMode === 'string')) {
13777 switch (this.viewMode) {
13790 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
13792 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13794 this.picker().on('mousedown', this.onMousedown, this);
13795 this.picker().on('click', this.onClick, this);
13797 this.picker().addClass('datepicker-dropdown');
13799 this.startViewMode = this.viewMode;
13802 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
13803 if(!this.calendarWeeks){
13808 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
13809 v.attr('colspan', function(i, val){
13810 return parseInt(val) + 1;
13815 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
13817 this.setStartDate(this.startDate);
13818 this.setEndDate(this.endDate);
13820 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
13827 if(this.isInline) {
13832 picker : function()
13834 return this.el.select('.datepicker', true).first();
13837 fillDow: function()
13839 var dowCnt = this.weekStart;
13848 if(this.calendarWeeks){
13856 while (dowCnt < this.weekStart + 7) {
13860 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
13864 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
13867 fillMonths: function()
13870 var months = this.picker().select('>.datepicker-months td', true).first();
13872 months.dom.innerHTML = '';
13878 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
13881 months.createChild(month);
13889 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
13891 if (this.date < this.startDate) {
13892 this.viewDate = new Date(this.startDate);
13893 } else if (this.date > this.endDate) {
13894 this.viewDate = new Date(this.endDate);
13896 this.viewDate = new Date(this.date);
13904 var d = new Date(this.viewDate),
13905 year = d.getUTCFullYear(),
13906 month = d.getUTCMonth(),
13907 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
13908 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
13909 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
13910 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
13911 currentDate = this.date && this.date.valueOf(),
13912 today = this.UTCToday();
13914 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
13916 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
13918 // this.picker.select('>tfoot th.today').
13919 // .text(dates[this.language].today)
13920 // .toggle(this.todayBtn !== false);
13922 this.updateNavArrows();
13925 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
13927 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
13929 prevMonth.setUTCDate(day);
13931 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
13933 var nextMonth = new Date(prevMonth);
13935 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
13937 nextMonth = nextMonth.valueOf();
13939 var fillMonths = false;
13941 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
13943 while(prevMonth.valueOf() < nextMonth) {
13946 if (prevMonth.getUTCDay() === this.weekStart) {
13948 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
13956 if(this.calendarWeeks){
13957 // ISO 8601: First week contains first thursday.
13958 // ISO also states week starts on Monday, but we can be more abstract here.
13960 // Start of current week: based on weekstart/current date
13961 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
13962 // Thursday of this week
13963 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
13964 // First Thursday of year, year from thursday
13965 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
13966 // Calendar week: ms between thursdays, div ms per day, div 7 days
13967 calWeek = (th - yth) / 864e5 / 7 + 1;
13969 fillMonths.cn.push({
13977 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
13979 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
13982 if (this.todayHighlight &&
13983 prevMonth.getUTCFullYear() == today.getFullYear() &&
13984 prevMonth.getUTCMonth() == today.getMonth() &&
13985 prevMonth.getUTCDate() == today.getDate()) {
13986 clsName += ' today';
13989 if (currentDate && prevMonth.valueOf() === currentDate) {
13990 clsName += ' active';
13993 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
13994 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
13995 clsName += ' disabled';
13998 fillMonths.cn.push({
14000 cls: 'day ' + clsName,
14001 html: prevMonth.getDate()
14004 prevMonth.setDate(prevMonth.getDate()+1);
14007 var currentYear = this.date && this.date.getUTCFullYear();
14008 var currentMonth = this.date && this.date.getUTCMonth();
14010 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14012 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14013 v.removeClass('active');
14015 if(currentYear === year && k === currentMonth){
14016 v.addClass('active');
14019 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14020 v.addClass('disabled');
14026 year = parseInt(year/10, 10) * 10;
14028 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14030 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14033 for (var i = -1; i < 11; i++) {
14034 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14036 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14044 showMode: function(dir)
14047 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14049 Roo.each(this.picker().select('>div',true).elements, function(v){
14050 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14053 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14058 if(this.isInline) return;
14060 this.picker().removeClass(['bottom', 'top']);
14062 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14064 * place to the top of element!
14068 this.picker().addClass('top');
14069 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14074 this.picker().addClass('bottom');
14076 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14079 parseDate : function(value)
14081 if(!value || value instanceof Date){
14084 var v = Date.parseDate(value, this.format);
14085 if (!v && this.useIso) {
14086 v = Date.parseDate(value, 'Y-m-d');
14088 if(!v && this.altFormats){
14089 if(!this.altFormatsArray){
14090 this.altFormatsArray = this.altFormats.split("|");
14092 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14093 v = Date.parseDate(value, this.altFormatsArray[i]);
14099 formatDate : function(date, fmt)
14101 return (!date || !(date instanceof Date)) ?
14102 date : date.dateFormat(fmt || this.format);
14105 onFocus : function()
14107 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14111 onBlur : function()
14113 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14115 var d = this.inputEl().getValue();
14126 this.picker().show();
14130 this.fireEvent('show', this, this.date);
14135 if(this.isInline) return;
14136 this.picker().hide();
14137 this.viewMode = this.startViewMode;
14140 this.fireEvent('hide', this, this.date);
14144 onMousedown: function(e)
14146 e.stopPropagation();
14147 e.preventDefault();
14152 Roo.bootstrap.DateField.superclass.keyup.call(this);
14156 setValue: function(v)
14158 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14160 var d = new Date(v);
14162 if(isNaN(d.getTime())){
14166 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14170 this.fireEvent('select', this, this.date);
14174 getValue: function()
14176 return this.formatDate(this.date);
14179 fireKey: function(e)
14181 if (!this.picker().isVisible()){
14182 if (e.keyCode == 27) // allow escape to hide and re-show picker
14186 var dateChanged = false,
14188 newDate, newViewDate;
14193 e.preventDefault();
14197 if (!this.keyboardNavigation) break;
14198 dir = e.keyCode == 37 ? -1 : 1;
14201 newDate = this.moveYear(this.date, dir);
14202 newViewDate = this.moveYear(this.viewDate, dir);
14203 } else if (e.shiftKey){
14204 newDate = this.moveMonth(this.date, dir);
14205 newViewDate = this.moveMonth(this.viewDate, dir);
14207 newDate = new Date(this.date);
14208 newDate.setUTCDate(this.date.getUTCDate() + dir);
14209 newViewDate = new Date(this.viewDate);
14210 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14212 if (this.dateWithinRange(newDate)){
14213 this.date = newDate;
14214 this.viewDate = newViewDate;
14215 this.setValue(this.formatDate(this.date));
14217 e.preventDefault();
14218 dateChanged = true;
14223 if (!this.keyboardNavigation) break;
14224 dir = e.keyCode == 38 ? -1 : 1;
14226 newDate = this.moveYear(this.date, dir);
14227 newViewDate = this.moveYear(this.viewDate, dir);
14228 } else if (e.shiftKey){
14229 newDate = this.moveMonth(this.date, dir);
14230 newViewDate = this.moveMonth(this.viewDate, dir);
14232 newDate = new Date(this.date);
14233 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14234 newViewDate = new Date(this.viewDate);
14235 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14237 if (this.dateWithinRange(newDate)){
14238 this.date = newDate;
14239 this.viewDate = newViewDate;
14240 this.setValue(this.formatDate(this.date));
14242 e.preventDefault();
14243 dateChanged = true;
14247 this.setValue(this.formatDate(this.date));
14249 e.preventDefault();
14252 this.setValue(this.formatDate(this.date));
14260 onClick: function(e)
14262 e.stopPropagation();
14263 e.preventDefault();
14265 var target = e.getTarget();
14267 if(target.nodeName.toLowerCase() === 'i'){
14268 target = Roo.get(target).dom.parentNode;
14271 var nodeName = target.nodeName;
14272 var className = target.className;
14273 var html = target.innerHTML;
14275 switch(nodeName.toLowerCase()) {
14277 switch(className) {
14283 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14284 switch(this.viewMode){
14286 this.viewDate = this.moveMonth(this.viewDate, dir);
14290 this.viewDate = this.moveYear(this.viewDate, dir);
14296 var date = new Date();
14297 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14299 this.setValue(this.formatDate(this.date));
14306 if (className.indexOf('disabled') === -1) {
14307 this.viewDate.setUTCDate(1);
14308 if (className.indexOf('month') !== -1) {
14309 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14311 var year = parseInt(html, 10) || 0;
14312 this.viewDate.setUTCFullYear(year);
14321 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
14322 var day = parseInt(html, 10) || 1;
14323 var year = this.viewDate.getUTCFullYear(),
14324 month = this.viewDate.getUTCMonth();
14326 if (className.indexOf('old') !== -1) {
14333 } else if (className.indexOf('new') !== -1) {
14341 this.date = this.UTCDate(year, month, day,0,0,0,0);
14342 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
14344 this.setValue(this.formatDate(this.date));
14351 setStartDate: function(startDate)
14353 this.startDate = startDate || -Infinity;
14354 if (this.startDate !== -Infinity) {
14355 this.startDate = this.parseDate(this.startDate);
14358 this.updateNavArrows();
14361 setEndDate: function(endDate)
14363 this.endDate = endDate || Infinity;
14364 if (this.endDate !== Infinity) {
14365 this.endDate = this.parseDate(this.endDate);
14368 this.updateNavArrows();
14371 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
14373 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
14374 if (typeof(this.daysOfWeekDisabled) !== 'object') {
14375 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
14377 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
14378 return parseInt(d, 10);
14381 this.updateNavArrows();
14384 updateNavArrows: function()
14386 var d = new Date(this.viewDate),
14387 year = d.getUTCFullYear(),
14388 month = d.getUTCMonth();
14390 Roo.each(this.picker().select('.prev', true).elements, function(v){
14392 switch (this.viewMode) {
14395 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
14401 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
14408 Roo.each(this.picker().select('.next', true).elements, function(v){
14410 switch (this.viewMode) {
14413 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
14419 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
14427 moveMonth: function(date, dir)
14429 if (!dir) return date;
14430 var new_date = new Date(date.valueOf()),
14431 day = new_date.getUTCDate(),
14432 month = new_date.getUTCMonth(),
14433 mag = Math.abs(dir),
14435 dir = dir > 0 ? 1 : -1;
14438 // If going back one month, make sure month is not current month
14439 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
14441 return new_date.getUTCMonth() == month;
14443 // If going forward one month, make sure month is as expected
14444 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
14446 return new_date.getUTCMonth() != new_month;
14448 new_month = month + dir;
14449 new_date.setUTCMonth(new_month);
14450 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
14451 if (new_month < 0 || new_month > 11)
14452 new_month = (new_month + 12) % 12;
14454 // For magnitudes >1, move one month at a time...
14455 for (var i=0; i<mag; i++)
14456 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
14457 new_date = this.moveMonth(new_date, dir);
14458 // ...then reset the day, keeping it in the new month
14459 new_month = new_date.getUTCMonth();
14460 new_date.setUTCDate(day);
14462 return new_month != new_date.getUTCMonth();
14465 // Common date-resetting loop -- if date is beyond end of month, make it
14468 new_date.setUTCDate(--day);
14469 new_date.setUTCMonth(new_month);
14474 moveYear: function(date, dir)
14476 return this.moveMonth(date, dir*12);
14479 dateWithinRange: function(date)
14481 return date >= this.startDate && date <= this.endDate;
14487 this.picker().remove();
14492 Roo.apply(Roo.bootstrap.DateField, {
14503 html: '<i class="fa fa-arrow-left"/>'
14513 html: '<i class="fa fa-arrow-right"/>'
14555 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
14556 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
14557 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
14558 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
14559 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
14572 navFnc: 'FullYear',
14577 navFnc: 'FullYear',
14582 Roo.apply(Roo.bootstrap.DateField, {
14586 cls: 'datepicker dropdown-menu',
14590 cls: 'datepicker-days',
14594 cls: 'table-condensed',
14596 Roo.bootstrap.DateField.head,
14600 Roo.bootstrap.DateField.footer
14607 cls: 'datepicker-months',
14611 cls: 'table-condensed',
14613 Roo.bootstrap.DateField.head,
14614 Roo.bootstrap.DateField.content,
14615 Roo.bootstrap.DateField.footer
14622 cls: 'datepicker-years',
14626 cls: 'table-condensed',
14628 Roo.bootstrap.DateField.head,
14629 Roo.bootstrap.DateField.content,
14630 Roo.bootstrap.DateField.footer
14649 * @class Roo.bootstrap.TimeField
14650 * @extends Roo.bootstrap.Input
14651 * Bootstrap DateField class
14655 * Create a new TimeField
14656 * @param {Object} config The config object
14659 Roo.bootstrap.TimeField = function(config){
14660 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
14664 * Fires when this field show.
14665 * @param {Roo.bootstrap.DateField} this
14666 * @param {Mixed} date The date value
14671 * Fires when this field hide.
14672 * @param {Roo.bootstrap.DateField} this
14673 * @param {Mixed} date The date value
14678 * Fires when select a date.
14679 * @param {Roo.bootstrap.DateField} this
14680 * @param {Mixed} date The date value
14686 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
14689 * @cfg {String} format
14690 * The default time format string which can be overriden for localization support. The format must be
14691 * valid according to {@link Date#parseDate} (defaults to 'H:i').
14695 onRender: function(ct, position)
14698 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
14700 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
14702 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14704 this.pop = this.picker().select('>.datepicker-time',true).first();
14705 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
14707 this.picker().on('mousedown', this.onMousedown, this);
14708 this.picker().on('click', this.onClick, this);
14710 this.picker().addClass('datepicker-dropdown');
14715 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
14716 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
14717 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
14718 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
14719 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
14720 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
14724 fireKey: function(e){
14725 if (!this.picker().isVisible()){
14726 if (e.keyCode == 27) // allow escape to hide and re-show picker
14731 e.preventDefault();
14739 this.onTogglePeriod();
14742 this.onIncrementMinutes();
14745 this.onDecrementMinutes();
14754 onClick: function(e) {
14755 e.stopPropagation();
14756 e.preventDefault();
14759 picker : function()
14761 return this.el.select('.datepicker', true).first();
14764 fillTime: function()
14766 var time = this.pop.select('tbody', true).first();
14768 time.dom.innerHTML = '';
14783 cls: 'hours-up glyphicon glyphicon-chevron-up'
14803 cls: 'minutes-up glyphicon glyphicon-chevron-up'
14824 cls: 'timepicker-hour',
14839 cls: 'timepicker-minute',
14854 cls: 'btn btn-primary period',
14876 cls: 'hours-down glyphicon glyphicon-chevron-down'
14896 cls: 'minutes-down glyphicon glyphicon-chevron-down'
14914 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
14921 var hours = this.time.getHours();
14922 var minutes = this.time.getMinutes();
14935 hours = hours - 12;
14939 hours = '0' + hours;
14943 minutes = '0' + minutes;
14946 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
14947 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
14948 this.pop.select('button', true).first().dom.innerHTML = period;
14954 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
14956 var cls = ['bottom'];
14958 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
14965 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
14970 this.picker().addClass(cls.join('-'));
14974 Roo.each(cls, function(c){
14976 _this.picker().setTop(_this.inputEl().getHeight());
14980 _this.picker().setTop(0 - _this.picker().getHeight());
14985 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
14989 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
14996 onFocus : function()
14998 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15002 onBlur : function()
15004 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15010 this.picker().show();
15015 this.fireEvent('show', this, this.date);
15020 this.picker().hide();
15023 this.fireEvent('hide', this, this.date);
15026 setTime : function()
15029 this.setValue(this.time.format(this.format));
15031 this.fireEvent('select', this, this.date);
15036 onMousedown: function(e){
15037 e.stopPropagation();
15038 e.preventDefault();
15041 onIncrementHours: function()
15043 Roo.log('onIncrementHours');
15044 this.time = this.time.add(Date.HOUR, 1);
15049 onDecrementHours: function()
15051 Roo.log('onDecrementHours');
15052 this.time = this.time.add(Date.HOUR, -1);
15056 onIncrementMinutes: function()
15058 Roo.log('onIncrementMinutes');
15059 this.time = this.time.add(Date.MINUTE, 1);
15063 onDecrementMinutes: function()
15065 Roo.log('onDecrementMinutes');
15066 this.time = this.time.add(Date.MINUTE, -1);
15070 onTogglePeriod: function()
15072 Roo.log('onTogglePeriod');
15073 this.time = this.time.add(Date.HOUR, 12);
15080 Roo.apply(Roo.bootstrap.TimeField, {
15110 cls: 'btn btn-info ok',
15122 Roo.apply(Roo.bootstrap.TimeField, {
15126 cls: 'datepicker dropdown-menu',
15130 cls: 'datepicker-time',
15134 cls: 'table-condensed',
15136 Roo.bootstrap.TimeField.content,
15137 Roo.bootstrap.TimeField.footer
15156 * @class Roo.bootstrap.CheckBox
15157 * @extends Roo.bootstrap.Input
15158 * Bootstrap CheckBox class
15160 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15161 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15162 * @cfg {String} boxLabel The text that appears beside the checkbox
15163 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15164 * @cfg {Boolean} checked initnal the element
15168 * Create a new CheckBox
15169 * @param {Object} config The config object
15172 Roo.bootstrap.CheckBox = function(config){
15173 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15178 * Fires when the element is checked or unchecked.
15179 * @param {Roo.bootstrap.CheckBox} this This input
15180 * @param {Boolean} checked The new checked value
15186 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15188 inputType: 'checkbox',
15195 getAutoCreate : function()
15197 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15203 cfg.cls = 'form-group checkbox' //input-group
15211 type : this.inputType,
15212 value : (!this.checked) ? this.valueOff : this.inputValue,
15213 cls : 'roo-checkbox', //'form-box',
15214 placeholder : this.placeholder || ''
15218 if (this.weight) { // Validity check?
15219 cfg.cls += " checkbox-" + this.weight;
15222 if (this.disabled) {
15223 input.disabled=true;
15227 input.checked = this.checked;
15231 input.name = this.name;
15235 input.cls += ' input-' + this.size;
15239 ['xs','sm','md','lg'].map(function(size){
15240 if (settings[size]) {
15241 cfg.cls += ' col-' + size + '-' + settings[size];
15247 var inputblock = input;
15252 if (this.before || this.after) {
15255 cls : 'input-group',
15259 inputblock.cn.push({
15261 cls : 'input-group-addon',
15265 inputblock.cn.push(input);
15267 inputblock.cn.push({
15269 cls : 'input-group-addon',
15276 if (align ==='left' && this.fieldLabel.length) {
15277 Roo.log("left and has label");
15283 cls : 'control-label col-md-' + this.labelWidth,
15284 html : this.fieldLabel
15288 cls : "col-md-" + (12 - this.labelWidth),
15295 } else if ( this.fieldLabel.length) {
15300 tag: this.boxLabel ? 'span' : 'label',
15302 cls: 'control-label box-input-label',
15303 //cls : 'input-group-addon',
15304 html : this.fieldLabel
15314 Roo.log(" no label && no align");
15315 cfg.cn = [ inputblock ] ;
15324 html: this.boxLabel
15336 * return the real input element.
15338 inputEl: function ()
15340 return this.el.select('input.roo-checkbox',true).first();
15345 return this.el.select('label.control-label',true).first();
15348 initEvents : function()
15350 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
15352 this.inputEl().on('click', this.onClick, this);
15356 onClick : function()
15358 this.setChecked(!this.checked);
15361 setChecked : function(state,suppressEvent)
15363 this.checked = state;
15365 this.inputEl().dom.checked = state;
15367 if(suppressEvent !== true){
15368 this.fireEvent('check', this, state);
15371 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15375 setValue : function(v,suppressEvent)
15377 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
15391 * @class Roo.bootstrap.Radio
15392 * @extends Roo.bootstrap.CheckBox
15393 * Bootstrap Radio class
15396 * Create a new Radio
15397 * @param {Object} config The config object
15400 Roo.bootstrap.Radio = function(config){
15401 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
15405 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
15407 inputType: 'radio',
15411 getAutoCreate : function()
15413 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15419 cfg.cls = 'form-group radio' //input-group
15424 type : this.inputType,
15425 value : (!this.checked) ? this.valueOff : this.inputValue,
15427 placeholder : this.placeholder || ''
15430 if (this.weight) { // Validity check?
15431 cfg.cls += " radio-" + this.weight;
15433 if (this.disabled) {
15434 input.disabled=true;
15438 input.checked = this.checked;
15442 input.name = this.name;
15446 input.cls += ' input-' + this.size;
15450 ['xs','sm','md','lg'].map(function(size){
15451 if (settings[size]) {
15452 cfg.cls += ' col-' + size + '-' + settings[size];
15456 var inputblock = input;
15458 if (this.before || this.after) {
15461 cls : 'input-group',
15465 inputblock.cn.push({
15467 cls : 'input-group-addon',
15471 inputblock.cn.push(input);
15473 inputblock.cn.push({
15475 cls : 'input-group-addon',
15482 if (align ==='left' && this.fieldLabel.length) {
15483 Roo.log("left and has label");
15489 cls : 'control-label col-md-' + this.labelWidth,
15490 html : this.fieldLabel
15494 cls : "col-md-" + (12 - this.labelWidth),
15501 } else if ( this.fieldLabel.length) {
15508 cls: 'control-label box-input-label',
15509 //cls : 'input-group-addon',
15510 html : this.fieldLabel
15520 Roo.log(" no label && no align");
15535 html: this.boxLabel
15542 inputEl: function ()
15544 return this.el.select('input.roo-radio',true).first();
15546 onClick : function()
15548 this.setChecked(true);
15551 setChecked : function(state,suppressEvent)
15554 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
15555 v.dom.checked = false;
15559 this.checked = state;
15560 this.inputEl().dom.checked = state;
15562 if(suppressEvent !== true){
15563 this.fireEvent('check', this, state);
15566 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15570 getGroupValue : function()
15573 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
15574 if(v.dom.checked == true){
15575 value = v.dom.value;
15583 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
15584 * @return {Mixed} value The field value
15586 getValue : function(){
15587 return this.getGroupValue();
15593 //<script type="text/javascript">
15596 * Based Ext JS Library 1.1.1
15597 * Copyright(c) 2006-2007, Ext JS, LLC.
15603 * @class Roo.HtmlEditorCore
15604 * @extends Roo.Component
15605 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
15607 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
15610 Roo.HtmlEditorCore = function(config){
15613 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
15616 * @event initialize
15617 * Fires when the editor is fully initialized (including the iframe)
15618 * @param {Roo.HtmlEditorCore} this
15623 * Fires when the editor is first receives the focus. Any insertion must wait
15624 * until after this event.
15625 * @param {Roo.HtmlEditorCore} this
15629 * @event beforesync
15630 * Fires before the textarea is updated with content from the editor iframe. Return false
15631 * to cancel the sync.
15632 * @param {Roo.HtmlEditorCore} this
15633 * @param {String} html
15637 * @event beforepush
15638 * Fires before the iframe editor is updated with content from the textarea. Return false
15639 * to cancel the push.
15640 * @param {Roo.HtmlEditorCore} this
15641 * @param {String} html
15646 * Fires when the textarea is updated with content from the editor iframe.
15647 * @param {Roo.HtmlEditorCore} this
15648 * @param {String} html
15653 * Fires when the iframe editor is updated with content from the textarea.
15654 * @param {Roo.HtmlEditorCore} this
15655 * @param {String} html
15660 * @event editorevent
15661 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
15662 * @param {Roo.HtmlEditorCore} this
15670 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
15674 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
15680 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
15685 * @cfg {Number} height (in pixels)
15689 * @cfg {Number} width (in pixels)
15694 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
15697 stylesheets: false,
15702 // private properties
15703 validationEvent : false,
15705 initialized : false,
15707 sourceEditMode : false,
15708 onFocus : Roo.emptyFn,
15710 hideMode:'offsets',
15718 * Protected method that will not generally be called directly. It
15719 * is called when the editor initializes the iframe with HTML contents. Override this method if you
15720 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
15722 getDocMarkup : function(){
15725 Roo.log(this.stylesheets);
15727 // inherit styels from page...??
15728 if (this.stylesheets === false) {
15730 Roo.get(document.head).select('style').each(function(node) {
15731 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
15734 Roo.get(document.head).select('link').each(function(node) {
15735 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
15738 } else if (!this.stylesheets.length) {
15740 st = '<style type="text/css">' +
15741 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
15744 Roo.each(this.stylesheets, function(s) {
15745 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
15750 st += '<style type="text/css">' +
15751 'IMG { cursor: pointer } ' +
15755 return '<html><head>' + st +
15756 //<style type="text/css">' +
15757 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
15759 ' </head><body class="roo-htmleditor-body"></body></html>';
15763 onRender : function(ct, position)
15766 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
15767 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
15770 this.el.dom.style.border = '0 none';
15771 this.el.dom.setAttribute('tabIndex', -1);
15772 this.el.addClass('x-hidden hide');
15776 if(Roo.isIE){ // fix IE 1px bogus margin
15777 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
15781 this.frameId = Roo.id();
15785 var iframe = this.owner.wrap.createChild({
15787 cls: 'form-control', // bootstrap..
15789 name: this.frameId,
15790 frameBorder : 'no',
15791 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
15796 this.iframe = iframe.dom;
15798 this.assignDocWin();
15800 this.doc.designMode = 'on';
15803 this.doc.write(this.getDocMarkup());
15807 var task = { // must defer to wait for browser to be ready
15809 //console.log("run task?" + this.doc.readyState);
15810 this.assignDocWin();
15811 if(this.doc.body || this.doc.readyState == 'complete'){
15813 this.doc.designMode="on";
15817 Roo.TaskMgr.stop(task);
15818 this.initEditor.defer(10, this);
15825 Roo.TaskMgr.start(task);
15832 onResize : function(w, h)
15834 Roo.log('resize: ' +w + ',' + h );
15835 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
15839 if(typeof w == 'number'){
15841 this.iframe.style.width = w + 'px';
15843 if(typeof h == 'number'){
15845 this.iframe.style.height = h + 'px';
15847 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
15854 * Toggles the editor between standard and source edit mode.
15855 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
15857 toggleSourceEdit : function(sourceEditMode){
15859 this.sourceEditMode = sourceEditMode === true;
15861 if(this.sourceEditMode){
15863 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
15866 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
15867 //this.iframe.className = '';
15870 //this.setSize(this.owner.wrap.getSize());
15871 //this.fireEvent('editmodechange', this, this.sourceEditMode);
15878 * Protected method that will not generally be called directly. If you need/want
15879 * custom HTML cleanup, this is the method you should override.
15880 * @param {String} html The HTML to be cleaned
15881 * return {String} The cleaned HTML
15883 cleanHtml : function(html){
15884 html = String(html);
15885 if(html.length > 5){
15886 if(Roo.isSafari){ // strip safari nonsense
15887 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
15890 if(html == ' '){
15897 * HTML Editor -> Textarea
15898 * Protected method that will not generally be called directly. Syncs the contents
15899 * of the editor iframe with the textarea.
15901 syncValue : function(){
15902 if(this.initialized){
15903 var bd = (this.doc.body || this.doc.documentElement);
15904 //this.cleanUpPaste(); -- this is done else where and causes havoc..
15905 var html = bd.innerHTML;
15907 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
15908 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
15910 html = '<div style="'+m[0]+'">' + html + '</div>';
15913 html = this.cleanHtml(html);
15914 // fix up the special chars.. normaly like back quotes in word...
15915 // however we do not want to do this with chinese..
15916 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
15917 var cc = b.charCodeAt();
15919 (cc >= 0x4E00 && cc < 0xA000 ) ||
15920 (cc >= 0x3400 && cc < 0x4E00 ) ||
15921 (cc >= 0xf900 && cc < 0xfb00 )
15927 if(this.owner.fireEvent('beforesync', this, html) !== false){
15928 this.el.dom.value = html;
15929 this.owner.fireEvent('sync', this, html);
15935 * Protected method that will not generally be called directly. Pushes the value of the textarea
15936 * into the iframe editor.
15938 pushValue : function(){
15939 if(this.initialized){
15940 var v = this.el.dom.value.trim();
15942 // if(v.length < 1){
15946 if(this.owner.fireEvent('beforepush', this, v) !== false){
15947 var d = (this.doc.body || this.doc.documentElement);
15949 this.cleanUpPaste();
15950 this.el.dom.value = d.innerHTML;
15951 this.owner.fireEvent('push', this, v);
15957 deferFocus : function(){
15958 this.focus.defer(10, this);
15962 focus : function(){
15963 if(this.win && !this.sourceEditMode){
15970 assignDocWin: function()
15972 var iframe = this.iframe;
15975 this.doc = iframe.contentWindow.document;
15976 this.win = iframe.contentWindow;
15978 if (!Roo.get(this.frameId)) {
15981 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
15982 this.win = Roo.get(this.frameId).dom.contentWindow;
15987 initEditor : function(){
15988 //console.log("INIT EDITOR");
15989 this.assignDocWin();
15993 this.doc.designMode="on";
15995 this.doc.write(this.getDocMarkup());
15998 var dbody = (this.doc.body || this.doc.documentElement);
15999 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16000 // this copies styles from the containing element into thsi one..
16001 // not sure why we need all of this..
16002 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16004 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16005 //ss['background-attachment'] = 'fixed'; // w3c
16006 dbody.bgProperties = 'fixed'; // ie
16007 //Roo.DomHelper.applyStyles(dbody, ss);
16008 Roo.EventManager.on(this.doc, {
16009 //'mousedown': this.onEditorEvent,
16010 'mouseup': this.onEditorEvent,
16011 'dblclick': this.onEditorEvent,
16012 'click': this.onEditorEvent,
16013 'keyup': this.onEditorEvent,
16018 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16020 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16021 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16023 this.initialized = true;
16025 this.owner.fireEvent('initialize', this);
16030 onDestroy : function(){
16036 //for (var i =0; i < this.toolbars.length;i++) {
16037 // // fixme - ask toolbars for heights?
16038 // this.toolbars[i].onDestroy();
16041 //this.wrap.dom.innerHTML = '';
16042 //this.wrap.remove();
16047 onFirstFocus : function(){
16049 this.assignDocWin();
16052 this.activated = true;
16055 if(Roo.isGecko){ // prevent silly gecko errors
16057 var s = this.win.getSelection();
16058 if(!s.focusNode || s.focusNode.nodeType != 3){
16059 var r = s.getRangeAt(0);
16060 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16065 this.execCmd('useCSS', true);
16066 this.execCmd('styleWithCSS', false);
16069 this.owner.fireEvent('activate', this);
16073 adjustFont: function(btn){
16074 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16075 //if(Roo.isSafari){ // safari
16078 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16079 if(Roo.isSafari){ // safari
16080 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16081 v = (v < 10) ? 10 : v;
16082 v = (v > 48) ? 48 : v;
16083 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16088 v = Math.max(1, v+adjust);
16090 this.execCmd('FontSize', v );
16093 onEditorEvent : function(e){
16094 this.owner.fireEvent('editorevent', this, e);
16095 // this.updateToolbar();
16096 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16099 insertTag : function(tg)
16101 // could be a bit smarter... -> wrap the current selected tRoo..
16102 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16104 range = this.createRange(this.getSelection());
16105 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16106 wrappingNode.appendChild(range.extractContents());
16107 range.insertNode(wrappingNode);
16114 this.execCmd("formatblock", tg);
16118 insertText : function(txt)
16122 var range = this.createRange();
16123 range.deleteContents();
16124 //alert(Sender.getAttribute('label'));
16126 range.insertNode(this.doc.createTextNode(txt));
16132 * Executes a Midas editor command on the editor document and performs necessary focus and
16133 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16134 * @param {String} cmd The Midas command
16135 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16137 relayCmd : function(cmd, value){
16139 this.execCmd(cmd, value);
16140 this.owner.fireEvent('editorevent', this);
16141 //this.updateToolbar();
16142 this.owner.deferFocus();
16146 * Executes a Midas editor command directly on the editor document.
16147 * For visual commands, you should use {@link #relayCmd} instead.
16148 * <b>This should only be called after the editor is initialized.</b>
16149 * @param {String} cmd The Midas command
16150 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16152 execCmd : function(cmd, value){
16153 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16160 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16162 * @param {String} text | dom node..
16164 insertAtCursor : function(text)
16169 if(!this.activated){
16175 var r = this.doc.selection.createRange();
16186 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16190 // from jquery ui (MIT licenced)
16192 var win = this.win;
16194 if (win.getSelection && win.getSelection().getRangeAt) {
16195 range = win.getSelection().getRangeAt(0);
16196 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16197 range.insertNode(node);
16198 } else if (win.document.selection && win.document.selection.createRange) {
16199 // no firefox support
16200 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16201 win.document.selection.createRange().pasteHTML(txt);
16203 // no firefox support
16204 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16205 this.execCmd('InsertHTML', txt);
16214 mozKeyPress : function(e){
16216 var c = e.getCharCode(), cmd;
16219 c = String.fromCharCode(c).toLowerCase();
16233 this.cleanUpPaste.defer(100, this);
16241 e.preventDefault();
16249 fixKeys : function(){ // load time branching for fastest keydown performance
16251 return function(e){
16252 var k = e.getKey(), r;
16255 r = this.doc.selection.createRange();
16258 r.pasteHTML('    ');
16265 r = this.doc.selection.createRange();
16267 var target = r.parentElement();
16268 if(!target || target.tagName.toLowerCase() != 'li'){
16270 r.pasteHTML('<br />');
16276 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16277 this.cleanUpPaste.defer(100, this);
16283 }else if(Roo.isOpera){
16284 return function(e){
16285 var k = e.getKey();
16289 this.execCmd('InsertHTML','    ');
16292 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16293 this.cleanUpPaste.defer(100, this);
16298 }else if(Roo.isSafari){
16299 return function(e){
16300 var k = e.getKey();
16304 this.execCmd('InsertText','\t');
16308 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16309 this.cleanUpPaste.defer(100, this);
16317 getAllAncestors: function()
16319 var p = this.getSelectedNode();
16322 a.push(p); // push blank onto stack..
16323 p = this.getParentElement();
16327 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
16331 a.push(this.doc.body);
16335 lastSelNode : false,
16338 getSelection : function()
16340 this.assignDocWin();
16341 return Roo.isIE ? this.doc.selection : this.win.getSelection();
16344 getSelectedNode: function()
16346 // this may only work on Gecko!!!
16348 // should we cache this!!!!
16353 var range = this.createRange(this.getSelection()).cloneRange();
16356 var parent = range.parentElement();
16358 var testRange = range.duplicate();
16359 testRange.moveToElementText(parent);
16360 if (testRange.inRange(range)) {
16363 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
16366 parent = parent.parentElement;
16371 // is ancestor a text element.
16372 var ac = range.commonAncestorContainer;
16373 if (ac.nodeType == 3) {
16374 ac = ac.parentNode;
16377 var ar = ac.childNodes;
16380 var other_nodes = [];
16381 var has_other_nodes = false;
16382 for (var i=0;i<ar.length;i++) {
16383 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
16386 // fullly contained node.
16388 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
16393 // probably selected..
16394 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
16395 other_nodes.push(ar[i]);
16399 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
16404 has_other_nodes = true;
16406 if (!nodes.length && other_nodes.length) {
16407 nodes= other_nodes;
16409 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
16415 createRange: function(sel)
16417 // this has strange effects when using with
16418 // top toolbar - not sure if it's a great idea.
16419 //this.editor.contentWindow.focus();
16420 if (typeof sel != "undefined") {
16422 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
16424 return this.doc.createRange();
16427 return this.doc.createRange();
16430 getParentElement: function()
16433 this.assignDocWin();
16434 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
16436 var range = this.createRange(sel);
16439 var p = range.commonAncestorContainer;
16440 while (p.nodeType == 3) { // text node
16451 * Range intersection.. the hard stuff...
16455 * [ -- selected range --- ]
16459 * if end is before start or hits it. fail.
16460 * if start is after end or hits it fail.
16462 * if either hits (but other is outside. - then it's not
16468 // @see http://www.thismuchiknow.co.uk/?p=64.
16469 rangeIntersectsNode : function(range, node)
16471 var nodeRange = node.ownerDocument.createRange();
16473 nodeRange.selectNode(node);
16475 nodeRange.selectNodeContents(node);
16478 var rangeStartRange = range.cloneRange();
16479 rangeStartRange.collapse(true);
16481 var rangeEndRange = range.cloneRange();
16482 rangeEndRange.collapse(false);
16484 var nodeStartRange = nodeRange.cloneRange();
16485 nodeStartRange.collapse(true);
16487 var nodeEndRange = nodeRange.cloneRange();
16488 nodeEndRange.collapse(false);
16490 return rangeStartRange.compareBoundaryPoints(
16491 Range.START_TO_START, nodeEndRange) == -1 &&
16492 rangeEndRange.compareBoundaryPoints(
16493 Range.START_TO_START, nodeStartRange) == 1;
16497 rangeCompareNode : function(range, node)
16499 var nodeRange = node.ownerDocument.createRange();
16501 nodeRange.selectNode(node);
16503 nodeRange.selectNodeContents(node);
16507 range.collapse(true);
16509 nodeRange.collapse(true);
16511 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
16512 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
16514 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
16516 var nodeIsBefore = ss == 1;
16517 var nodeIsAfter = ee == -1;
16519 if (nodeIsBefore && nodeIsAfter)
16521 if (!nodeIsBefore && nodeIsAfter)
16522 return 1; //right trailed.
16524 if (nodeIsBefore && !nodeIsAfter)
16525 return 2; // left trailed.
16530 // private? - in a new class?
16531 cleanUpPaste : function()
16533 // cleans up the whole document..
16534 Roo.log('cleanuppaste');
16536 this.cleanUpChildren(this.doc.body);
16537 var clean = this.cleanWordChars(this.doc.body.innerHTML);
16538 if (clean != this.doc.body.innerHTML) {
16539 this.doc.body.innerHTML = clean;
16544 cleanWordChars : function(input) {// change the chars to hex code
16545 var he = Roo.HtmlEditorCore;
16547 var output = input;
16548 Roo.each(he.swapCodes, function(sw) {
16549 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
16551 output = output.replace(swapper, sw[1]);
16558 cleanUpChildren : function (n)
16560 if (!n.childNodes.length) {
16563 for (var i = n.childNodes.length-1; i > -1 ; i--) {
16564 this.cleanUpChild(n.childNodes[i]);
16571 cleanUpChild : function (node)
16574 //console.log(node);
16575 if (node.nodeName == "#text") {
16576 // clean up silly Windows -- stuff?
16579 if (node.nodeName == "#comment") {
16580 node.parentNode.removeChild(node);
16581 // clean up silly Windows -- stuff?
16585 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
16587 node.parentNode.removeChild(node);
16592 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
16594 // remove <a name=....> as rendering on yahoo mailer is borked with this.
16595 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
16597 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
16598 // remove_keep_children = true;
16601 if (remove_keep_children) {
16602 this.cleanUpChildren(node);
16603 // inserts everything just before this node...
16604 while (node.childNodes.length) {
16605 var cn = node.childNodes[0];
16606 node.removeChild(cn);
16607 node.parentNode.insertBefore(cn, node);
16609 node.parentNode.removeChild(node);
16613 if (!node.attributes || !node.attributes.length) {
16614 this.cleanUpChildren(node);
16618 function cleanAttr(n,v)
16621 if (v.match(/^\./) || v.match(/^\//)) {
16624 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
16627 if (v.match(/^#/)) {
16630 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
16631 node.removeAttribute(n);
16635 function cleanStyle(n,v)
16637 if (v.match(/expression/)) { //XSS?? should we even bother..
16638 node.removeAttribute(n);
16641 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
16642 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
16645 var parts = v.split(/;/);
16648 Roo.each(parts, function(p) {
16649 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
16653 var l = p.split(':').shift().replace(/\s+/g,'');
16654 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
16656 if ( cblack.indexOf(l) > -1) {
16657 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
16658 //node.removeAttribute(n);
16662 // only allow 'c whitelisted system attributes'
16663 if ( cwhite.length && cwhite.indexOf(l) < 0) {
16664 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
16665 //node.removeAttribute(n);
16675 if (clean.length) {
16676 node.setAttribute(n, clean.join(';'));
16678 node.removeAttribute(n);
16684 for (var i = node.attributes.length-1; i > -1 ; i--) {
16685 var a = node.attributes[i];
16688 if (a.name.toLowerCase().substr(0,2)=='on') {
16689 node.removeAttribute(a.name);
16692 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
16693 node.removeAttribute(a.name);
16696 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
16697 cleanAttr(a.name,a.value); // fixme..
16700 if (a.name == 'style') {
16701 cleanStyle(a.name,a.value);
16704 /// clean up MS crap..
16705 // tecnically this should be a list of valid class'es..
16708 if (a.name == 'class') {
16709 if (a.value.match(/^Mso/)) {
16710 node.className = '';
16713 if (a.value.match(/body/)) {
16714 node.className = '';
16725 this.cleanUpChildren(node);
16730 * Clean up MS wordisms...
16732 cleanWord : function(node)
16735 var cleanWordChildren = function()
16737 if (!node.childNodes.length) {
16740 for (var i = node.childNodes.length-1; i > -1 ; i--) {
16741 _t.cleanWord(node.childNodes[i]);
16747 this.cleanWord(this.doc.body);
16750 if (node.nodeName == "#text") {
16751 // clean up silly Windows -- stuff?
16754 if (node.nodeName == "#comment") {
16755 node.parentNode.removeChild(node);
16756 // clean up silly Windows -- stuff?
16760 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
16761 node.parentNode.removeChild(node);
16765 // remove - but keep children..
16766 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
16767 while (node.childNodes.length) {
16768 var cn = node.childNodes[0];
16769 node.removeChild(cn);
16770 node.parentNode.insertBefore(cn, node);
16772 node.parentNode.removeChild(node);
16773 cleanWordChildren();
16777 if (node.className.length) {
16779 var cn = node.className.split(/\W+/);
16781 Roo.each(cn, function(cls) {
16782 if (cls.match(/Mso[a-zA-Z]+/)) {
16787 node.className = cna.length ? cna.join(' ') : '';
16789 node.removeAttribute("class");
16793 if (node.hasAttribute("lang")) {
16794 node.removeAttribute("lang");
16797 if (node.hasAttribute("style")) {
16799 var styles = node.getAttribute("style").split(";");
16801 Roo.each(styles, function(s) {
16802 if (!s.match(/:/)) {
16805 var kv = s.split(":");
16806 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
16809 // what ever is left... we allow.
16812 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
16813 if (!nstyle.length) {
16814 node.removeAttribute('style');
16818 cleanWordChildren();
16822 domToHTML : function(currentElement, depth, nopadtext) {
16824 depth = depth || 0;
16825 nopadtext = nopadtext || false;
16827 if (!currentElement) {
16828 return this.domToHTML(this.doc.body);
16831 //Roo.log(currentElement);
16833 var allText = false;
16834 var nodeName = currentElement.nodeName;
16835 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
16837 if (nodeName == '#text') {
16838 return currentElement.nodeValue;
16843 if (nodeName != 'BODY') {
16846 // Prints the node tagName, such as <A>, <IMG>, etc
16849 for(i = 0; i < currentElement.attributes.length;i++) {
16851 var aname = currentElement.attributes.item(i).name;
16852 if (!currentElement.attributes.item(i).value.length) {
16855 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
16858 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
16867 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
16870 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
16875 // Traverse the tree
16877 var currentElementChild = currentElement.childNodes.item(i);
16878 var allText = true;
16879 var innerHTML = '';
16881 while (currentElementChild) {
16882 // Formatting code (indent the tree so it looks nice on the screen)
16883 var nopad = nopadtext;
16884 if (lastnode == 'SPAN') {
16888 if (currentElementChild.nodeName == '#text') {
16889 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
16890 if (!nopad && toadd.length > 80) {
16891 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
16893 innerHTML += toadd;
16896 currentElementChild = currentElement.childNodes.item(i);
16902 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
16904 // Recursively traverse the tree structure of the child node
16905 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
16906 lastnode = currentElementChild.nodeName;
16908 currentElementChild=currentElement.childNodes.item(i);
16914 // The remaining code is mostly for formatting the tree
16915 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
16920 ret+= "</"+tagName+">";
16926 // hide stuff that is not compatible
16940 * @event specialkey
16944 * @cfg {String} fieldClass @hide
16947 * @cfg {String} focusClass @hide
16950 * @cfg {String} autoCreate @hide
16953 * @cfg {String} inputType @hide
16956 * @cfg {String} invalidClass @hide
16959 * @cfg {String} invalidText @hide
16962 * @cfg {String} msgFx @hide
16965 * @cfg {String} validateOnBlur @hide
16969 Roo.HtmlEditorCore.white = [
16970 'area', 'br', 'img', 'input', 'hr', 'wbr',
16972 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
16973 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
16974 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
16975 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
16976 'table', 'ul', 'xmp',
16978 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
16981 'dir', 'menu', 'ol', 'ul', 'dl',
16987 Roo.HtmlEditorCore.black = [
16988 // 'embed', 'object', // enable - backend responsiblity to clean thiese
16990 'base', 'basefont', 'bgsound', 'blink', 'body',
16991 'frame', 'frameset', 'head', 'html', 'ilayer',
16992 'iframe', 'layer', 'link', 'meta', 'object',
16993 'script', 'style' ,'title', 'xml' // clean later..
16995 Roo.HtmlEditorCore.clean = [
16996 'script', 'style', 'title', 'xml'
16998 Roo.HtmlEditorCore.remove = [
17003 Roo.HtmlEditorCore.ablack = [
17007 Roo.HtmlEditorCore.aclean = [
17008 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17012 Roo.HtmlEditorCore.pwhite= [
17013 'http', 'https', 'mailto'
17016 // white listed style attributes.
17017 Roo.HtmlEditorCore.cwhite= [
17018 // 'text-align', /// default is to allow most things..
17024 // black listed style attributes.
17025 Roo.HtmlEditorCore.cblack= [
17026 // 'font-size' -- this can be set by the project
17030 Roo.HtmlEditorCore.swapCodes =[
17049 * @class Roo.bootstrap.HtmlEditor
17050 * @extends Roo.bootstrap.TextArea
17051 * Bootstrap HtmlEditor class
17054 * Create a new HtmlEditor
17055 * @param {Object} config The config object
17058 Roo.bootstrap.HtmlEditor = function(config){
17059 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17060 if (!this.toolbars) {
17061 this.toolbars = [];
17063 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17066 * @event initialize
17067 * Fires when the editor is fully initialized (including the iframe)
17068 * @param {HtmlEditor} this
17073 * Fires when the editor is first receives the focus. Any insertion must wait
17074 * until after this event.
17075 * @param {HtmlEditor} this
17079 * @event beforesync
17080 * Fires before the textarea is updated with content from the editor iframe. Return false
17081 * to cancel the sync.
17082 * @param {HtmlEditor} this
17083 * @param {String} html
17087 * @event beforepush
17088 * Fires before the iframe editor is updated with content from the textarea. Return false
17089 * to cancel the push.
17090 * @param {HtmlEditor} this
17091 * @param {String} html
17096 * Fires when the textarea is updated with content from the editor iframe.
17097 * @param {HtmlEditor} this
17098 * @param {String} html
17103 * Fires when the iframe editor is updated with content from the textarea.
17104 * @param {HtmlEditor} this
17105 * @param {String} html
17109 * @event editmodechange
17110 * Fires when the editor switches edit modes
17111 * @param {HtmlEditor} this
17112 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17114 editmodechange: true,
17116 * @event editorevent
17117 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17118 * @param {HtmlEditor} this
17122 * @event firstfocus
17123 * Fires when on first focus - needed by toolbars..
17124 * @param {HtmlEditor} this
17129 * Auto save the htmlEditor value as a file into Events
17130 * @param {HtmlEditor} this
17134 * @event savedpreview
17135 * preview the saved version of htmlEditor
17136 * @param {HtmlEditor} this
17143 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17147 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17152 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17157 * @cfg {Number} height (in pixels)
17161 * @cfg {Number} width (in pixels)
17166 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17169 stylesheets: false,
17174 // private properties
17175 validationEvent : false,
17177 initialized : false,
17180 onFocus : Roo.emptyFn,
17182 hideMode:'offsets',
17185 tbContainer : false,
17187 toolbarContainer :function() {
17188 return this.wrap.select('.x-html-editor-tb',true).first();
17192 * Protected method that will not generally be called directly. It
17193 * is called when the editor creates its toolbar. Override this method if you need to
17194 * add custom toolbar buttons.
17195 * @param {HtmlEditor} editor
17197 createToolbar : function(){
17199 Roo.log("create toolbars");
17201 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17202 this.toolbars[0].render(this.toolbarContainer());
17206 // if (!editor.toolbars || !editor.toolbars.length) {
17207 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17210 // for (var i =0 ; i < editor.toolbars.length;i++) {
17211 // editor.toolbars[i] = Roo.factory(
17212 // typeof(editor.toolbars[i]) == 'string' ?
17213 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
17214 // Roo.bootstrap.HtmlEditor);
17215 // editor.toolbars[i].init(editor);
17221 onRender : function(ct, position)
17223 // Roo.log("Call onRender: " + this.xtype);
17225 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17227 this.wrap = this.inputEl().wrap({
17228 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17231 this.editorcore.onRender(ct, position);
17233 if (this.resizable) {
17234 this.resizeEl = new Roo.Resizable(this.wrap, {
17238 minHeight : this.height,
17239 height: this.height,
17240 handles : this.resizable,
17243 resize : function(r, w, h) {
17244 _t.onResize(w,h); // -something
17250 this.createToolbar(this);
17253 if(!this.width && this.resizable){
17254 this.setSize(this.wrap.getSize());
17256 if (this.resizeEl) {
17257 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17258 // should trigger onReize..
17264 onResize : function(w, h)
17266 Roo.log('resize: ' +w + ',' + h );
17267 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17271 if(this.inputEl() ){
17272 if(typeof w == 'number'){
17273 var aw = w - this.wrap.getFrameWidth('lr');
17274 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17277 if(typeof h == 'number'){
17278 var tbh = -11; // fixme it needs to tool bar size!
17279 for (var i =0; i < this.toolbars.length;i++) {
17280 // fixme - ask toolbars for heights?
17281 tbh += this.toolbars[i].el.getHeight();
17282 //if (this.toolbars[i].footer) {
17283 // tbh += this.toolbars[i].footer.el.getHeight();
17291 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17292 ah -= 5; // knock a few pixes off for look..
17293 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17297 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17298 this.editorcore.onResize(ew,eh);
17303 * Toggles the editor between standard and source edit mode.
17304 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17306 toggleSourceEdit : function(sourceEditMode)
17308 this.editorcore.toggleSourceEdit(sourceEditMode);
17310 if(this.editorcore.sourceEditMode){
17311 Roo.log('editor - showing textarea');
17314 // Roo.log(this.syncValue());
17316 this.inputEl().removeClass(['hide', 'x-hidden']);
17317 this.inputEl().dom.removeAttribute('tabIndex');
17318 this.inputEl().focus();
17320 Roo.log('editor - hiding textarea');
17322 // Roo.log(this.pushValue());
17325 this.inputEl().addClass(['hide', 'x-hidden']);
17326 this.inputEl().dom.setAttribute('tabIndex', -1);
17327 //this.deferFocus();
17330 if(this.resizable){
17331 this.setSize(this.wrap.getSize());
17334 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
17337 // private (for BoxComponent)
17338 adjustSize : Roo.BoxComponent.prototype.adjustSize,
17340 // private (for BoxComponent)
17341 getResizeEl : function(){
17345 // private (for BoxComponent)
17346 getPositionEl : function(){
17351 initEvents : function(){
17352 this.originalValue = this.getValue();
17356 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17359 // markInvalid : Roo.emptyFn,
17361 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17364 // clearInvalid : Roo.emptyFn,
17366 setValue : function(v){
17367 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
17368 this.editorcore.pushValue();
17373 deferFocus : function(){
17374 this.focus.defer(10, this);
17378 focus : function(){
17379 this.editorcore.focus();
17385 onDestroy : function(){
17391 for (var i =0; i < this.toolbars.length;i++) {
17392 // fixme - ask toolbars for heights?
17393 this.toolbars[i].onDestroy();
17396 this.wrap.dom.innerHTML = '';
17397 this.wrap.remove();
17402 onFirstFocus : function(){
17403 //Roo.log("onFirstFocus");
17404 this.editorcore.onFirstFocus();
17405 for (var i =0; i < this.toolbars.length;i++) {
17406 this.toolbars[i].onFirstFocus();
17412 syncValue : function()
17414 this.editorcore.syncValue();
17417 pushValue : function()
17419 this.editorcore.pushValue();
17423 // hide stuff that is not compatible
17437 * @event specialkey
17441 * @cfg {String} fieldClass @hide
17444 * @cfg {String} focusClass @hide
17447 * @cfg {String} autoCreate @hide
17450 * @cfg {String} inputType @hide
17453 * @cfg {String} invalidClass @hide
17456 * @cfg {String} invalidText @hide
17459 * @cfg {String} msgFx @hide
17462 * @cfg {String} validateOnBlur @hide
17471 Roo.namespace('Roo.bootstrap.htmleditor');
17473 * @class Roo.bootstrap.HtmlEditorToolbar1
17478 new Roo.bootstrap.HtmlEditor({
17481 new Roo.bootstrap.HtmlEditorToolbar1({
17482 disable : { fonts: 1 , format: 1, ..., ... , ...],
17488 * @cfg {Object} disable List of elements to disable..
17489 * @cfg {Array} btns List of additional buttons.
17493 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
17496 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
17499 Roo.apply(this, config);
17501 // default disabled, based on 'good practice'..
17502 this.disable = this.disable || {};
17503 Roo.applyIf(this.disable, {
17506 specialElements : true
17508 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
17510 this.editor = config.editor;
17511 this.editorcore = config.editor.editorcore;
17513 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
17515 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
17516 // dont call parent... till later.
17518 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
17523 editorcore : false,
17528 "h1","h2","h3","h4","h5","h6",
17530 "abbr", "acronym", "address", "cite", "samp", "var",
17534 onRender : function(ct, position)
17536 // Roo.log("Call onRender: " + this.xtype);
17538 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
17540 this.el.dom.style.marginBottom = '0';
17542 var editorcore = this.editorcore;
17543 var editor= this.editor;
17546 var btn = function(id,cmd , toggle, handler){
17548 var event = toggle ? 'toggle' : 'click';
17553 xns: Roo.bootstrap,
17556 enableToggle:toggle !== false,
17558 pressed : toggle ? false : null,
17561 a.listeners[toggle ? 'toggle' : 'click'] = function() {
17562 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
17571 xns: Roo.bootstrap,
17572 glyphicon : 'font',
17576 xns: Roo.bootstrap,
17580 Roo.each(this.formats, function(f) {
17581 style.menu.items.push({
17583 xns: Roo.bootstrap,
17584 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
17589 editorcore.insertTag(this.tagname);
17596 children.push(style);
17599 btn('bold',false,true);
17600 btn('italic',false,true);
17601 btn('align-left', 'justifyleft',true);
17602 btn('align-center', 'justifycenter',true);
17603 btn('align-right' , 'justifyright',true);
17604 btn('link', false, false, function(btn) {
17605 //Roo.log("create link?");
17606 var url = prompt(this.createLinkText, this.defaultLinkValue);
17607 if(url && url != 'http:/'+'/'){
17608 this.editorcore.relayCmd('createlink', url);
17611 btn('list','insertunorderedlist',true);
17612 btn('pencil', false,true, function(btn){
17615 this.toggleSourceEdit(btn.pressed);
17621 xns: Roo.bootstrap,
17626 xns: Roo.bootstrap,
17631 cog.menu.items.push({
17633 xns: Roo.bootstrap,
17634 html : Clean styles,
17639 editorcore.insertTag(this.tagname);
17648 this.xtype = 'NavSimplebar';
17650 for(var i=0;i< children.length;i++) {
17652 this.buttons.add(this.addxtypeChild(children[i]));
17656 editor.on('editorevent', this.updateToolbar, this);
17658 onBtnClick : function(id)
17660 this.editorcore.relayCmd(id);
17661 this.editorcore.focus();
17665 * Protected method that will not generally be called directly. It triggers
17666 * a toolbar update by reading the markup state of the current selection in the editor.
17668 updateToolbar: function(){
17670 if(!this.editorcore.activated){
17671 this.editor.onFirstFocus(); // is this neeed?
17675 var btns = this.buttons;
17676 var doc = this.editorcore.doc;
17677 btns.get('bold').setActive(doc.queryCommandState('bold'));
17678 btns.get('italic').setActive(doc.queryCommandState('italic'));
17679 //btns.get('underline').setActive(doc.queryCommandState('underline'));
17681 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
17682 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
17683 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
17685 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
17686 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
17689 var ans = this.editorcore.getAllAncestors();
17690 if (this.formatCombo) {
17693 var store = this.formatCombo.store;
17694 this.formatCombo.setValue("");
17695 for (var i =0; i < ans.length;i++) {
17696 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
17698 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
17706 // hides menus... - so this cant be on a menu...
17707 Roo.bootstrap.MenuMgr.hideAll();
17709 Roo.bootstrap.MenuMgr.hideAll();
17710 //this.editorsyncValue();
17712 onFirstFocus: function() {
17713 this.buttons.each(function(item){
17717 toggleSourceEdit : function(sourceEditMode){
17720 if(sourceEditMode){
17721 Roo.log("disabling buttons");
17722 this.buttons.each( function(item){
17723 if(item.cmd != 'pencil'){
17729 Roo.log("enabling buttons");
17730 if(this.editorcore.initialized){
17731 this.buttons.each( function(item){
17737 Roo.log("calling toggole on editor");
17738 // tell the editor that it's been pressed..
17739 this.editor.toggleSourceEdit(sourceEditMode);
17749 * @class Roo.bootstrap.Table.AbstractSelectionModel
17750 * @extends Roo.util.Observable
17751 * Abstract base class for grid SelectionModels. It provides the interface that should be
17752 * implemented by descendant classes. This class should not be directly instantiated.
17755 Roo.bootstrap.Table.AbstractSelectionModel = function(){
17756 this.locked = false;
17757 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
17761 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
17762 /** @ignore Called by the grid automatically. Do not call directly. */
17763 init : function(grid){
17769 * Locks the selections.
17772 this.locked = true;
17776 * Unlocks the selections.
17778 unlock : function(){
17779 this.locked = false;
17783 * Returns true if the selections are locked.
17784 * @return {Boolean}
17786 isLocked : function(){
17787 return this.locked;
17791 * @extends Roo.bootstrap.Table.AbstractSelectionModel
17792 * @class Roo.bootstrap.Table.RowSelectionModel
17793 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
17794 * It supports multiple selections and keyboard selection/navigation.
17796 * @param {Object} config
17799 Roo.bootstrap.Table.RowSelectionModel = function(config){
17800 Roo.apply(this, config);
17801 this.selections = new Roo.util.MixedCollection(false, function(o){
17806 this.lastActive = false;
17810 * @event selectionchange
17811 * Fires when the selection changes
17812 * @param {SelectionModel} this
17814 "selectionchange" : true,
17816 * @event afterselectionchange
17817 * Fires after the selection changes (eg. by key press or clicking)
17818 * @param {SelectionModel} this
17820 "afterselectionchange" : true,
17822 * @event beforerowselect
17823 * Fires when a row is selected being selected, return false to cancel.
17824 * @param {SelectionModel} this
17825 * @param {Number} rowIndex The selected index
17826 * @param {Boolean} keepExisting False if other selections will be cleared
17828 "beforerowselect" : true,
17831 * Fires when a row is selected.
17832 * @param {SelectionModel} this
17833 * @param {Number} rowIndex The selected index
17834 * @param {Roo.data.Record} r The record
17836 "rowselect" : true,
17838 * @event rowdeselect
17839 * Fires when a row is deselected.
17840 * @param {SelectionModel} this
17841 * @param {Number} rowIndex The selected index
17843 "rowdeselect" : true
17845 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
17846 this.locked = false;
17849 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
17851 * @cfg {Boolean} singleSelect
17852 * True to allow selection of only one row at a time (defaults to false)
17854 singleSelect : false,
17857 initEvents : function(){
17859 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
17860 this.grid.on("mousedown", this.handleMouseDown, this);
17861 }else{ // allow click to work like normal
17862 this.grid.on("rowclick", this.handleDragableRowClick, this);
17865 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
17866 "up" : function(e){
17868 this.selectPrevious(e.shiftKey);
17869 }else if(this.last !== false && this.lastActive !== false){
17870 var last = this.last;
17871 this.selectRange(this.last, this.lastActive-1);
17872 this.grid.getView().focusRow(this.lastActive);
17873 if(last !== false){
17877 this.selectFirstRow();
17879 this.fireEvent("afterselectionchange", this);
17881 "down" : function(e){
17883 this.selectNext(e.shiftKey);
17884 }else if(this.last !== false && this.lastActive !== false){
17885 var last = this.last;
17886 this.selectRange(this.last, this.lastActive+1);
17887 this.grid.getView().focusRow(this.lastActive);
17888 if(last !== false){
17892 this.selectFirstRow();
17894 this.fireEvent("afterselectionchange", this);
17899 var view = this.grid.view;
17900 view.on("refresh", this.onRefresh, this);
17901 view.on("rowupdated", this.onRowUpdated, this);
17902 view.on("rowremoved", this.onRemove, this);
17906 onRefresh : function(){
17907 var ds = this.grid.dataSource, i, v = this.grid.view;
17908 var s = this.selections;
17909 s.each(function(r){
17910 if((i = ds.indexOfId(r.id)) != -1){
17919 onRemove : function(v, index, r){
17920 this.selections.remove(r);
17924 onRowUpdated : function(v, index, r){
17925 if(this.isSelected(r)){
17926 v.onRowSelect(index);
17932 * @param {Array} records The records to select
17933 * @param {Boolean} keepExisting (optional) True to keep existing selections
17935 selectRecords : function(records, keepExisting){
17937 this.clearSelections();
17939 var ds = this.grid.dataSource;
17940 for(var i = 0, len = records.length; i < len; i++){
17941 this.selectRow(ds.indexOf(records[i]), true);
17946 * Gets the number of selected rows.
17949 getCount : function(){
17950 return this.selections.length;
17954 * Selects the first row in the grid.
17956 selectFirstRow : function(){
17961 * Select the last row.
17962 * @param {Boolean} keepExisting (optional) True to keep existing selections
17964 selectLastRow : function(keepExisting){
17965 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
17969 * Selects the row immediately following the last selected row.
17970 * @param {Boolean} keepExisting (optional) True to keep existing selections
17972 selectNext : function(keepExisting){
17973 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
17974 this.selectRow(this.last+1, keepExisting);
17975 this.grid.getView().focusRow(this.last);
17980 * Selects the row that precedes the last selected row.
17981 * @param {Boolean} keepExisting (optional) True to keep existing selections
17983 selectPrevious : function(keepExisting){
17985 this.selectRow(this.last-1, keepExisting);
17986 this.grid.getView().focusRow(this.last);
17991 * Returns the selected records
17992 * @return {Array} Array of selected records
17994 getSelections : function(){
17995 return [].concat(this.selections.items);
17999 * Returns the first selected record.
18002 getSelected : function(){
18003 return this.selections.itemAt(0);
18008 * Clears all selections.
18010 clearSelections : function(fast){
18011 if(this.locked) return;
18013 var ds = this.grid.dataSource;
18014 var s = this.selections;
18015 s.each(function(r){
18016 this.deselectRow(ds.indexOfId(r.id));
18020 this.selections.clear();
18027 * Selects all rows.
18029 selectAll : function(){
18030 if(this.locked) return;
18031 this.selections.clear();
18032 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18033 this.selectRow(i, true);
18038 * Returns True if there is a selection.
18039 * @return {Boolean}
18041 hasSelection : function(){
18042 return this.selections.length > 0;
18046 * Returns True if the specified row is selected.
18047 * @param {Number/Record} record The record or index of the record to check
18048 * @return {Boolean}
18050 isSelected : function(index){
18051 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18052 return (r && this.selections.key(r.id) ? true : false);
18056 * Returns True if the specified record id is selected.
18057 * @param {String} id The id of record to check
18058 * @return {Boolean}
18060 isIdSelected : function(id){
18061 return (this.selections.key(id) ? true : false);
18065 handleMouseDown : function(e, t){
18066 var view = this.grid.getView(), rowIndex;
18067 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18070 if(e.shiftKey && this.last !== false){
18071 var last = this.last;
18072 this.selectRange(last, rowIndex, e.ctrlKey);
18073 this.last = last; // reset the last
18074 view.focusRow(rowIndex);
18076 var isSelected = this.isSelected(rowIndex);
18077 if(e.button !== 0 && isSelected){
18078 view.focusRow(rowIndex);
18079 }else if(e.ctrlKey && isSelected){
18080 this.deselectRow(rowIndex);
18081 }else if(!isSelected){
18082 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18083 view.focusRow(rowIndex);
18086 this.fireEvent("afterselectionchange", this);
18089 handleDragableRowClick : function(grid, rowIndex, e)
18091 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18092 this.selectRow(rowIndex, false);
18093 grid.view.focusRow(rowIndex);
18094 this.fireEvent("afterselectionchange", this);
18099 * Selects multiple rows.
18100 * @param {Array} rows Array of the indexes of the row to select
18101 * @param {Boolean} keepExisting (optional) True to keep existing selections
18103 selectRows : function(rows, keepExisting){
18105 this.clearSelections();
18107 for(var i = 0, len = rows.length; i < len; i++){
18108 this.selectRow(rows[i], true);
18113 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18114 * @param {Number} startRow The index of the first row in the range
18115 * @param {Number} endRow The index of the last row in the range
18116 * @param {Boolean} keepExisting (optional) True to retain existing selections
18118 selectRange : function(startRow, endRow, keepExisting){
18119 if(this.locked) return;
18121 this.clearSelections();
18123 if(startRow <= endRow){
18124 for(var i = startRow; i <= endRow; i++){
18125 this.selectRow(i, true);
18128 for(var i = startRow; i >= endRow; i--){
18129 this.selectRow(i, true);
18135 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18136 * @param {Number} startRow The index of the first row in the range
18137 * @param {Number} endRow The index of the last row in the range
18139 deselectRange : function(startRow, endRow, preventViewNotify){
18140 if(this.locked) return;
18141 for(var i = startRow; i <= endRow; i++){
18142 this.deselectRow(i, preventViewNotify);
18148 * @param {Number} row The index of the row to select
18149 * @param {Boolean} keepExisting (optional) True to keep existing selections
18151 selectRow : function(index, keepExisting, preventViewNotify){
18152 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18153 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18154 if(!keepExisting || this.singleSelect){
18155 this.clearSelections();
18157 var r = this.grid.dataSource.getAt(index);
18158 this.selections.add(r);
18159 this.last = this.lastActive = index;
18160 if(!preventViewNotify){
18161 this.grid.getView().onRowSelect(index);
18163 this.fireEvent("rowselect", this, index, r);
18164 this.fireEvent("selectionchange", this);
18170 * @param {Number} row The index of the row to deselect
18172 deselectRow : function(index, preventViewNotify){
18173 if(this.locked) return;
18174 if(this.last == index){
18177 if(this.lastActive == index){
18178 this.lastActive = false;
18180 var r = this.grid.dataSource.getAt(index);
18181 this.selections.remove(r);
18182 if(!preventViewNotify){
18183 this.grid.getView().onRowDeselect(index);
18185 this.fireEvent("rowdeselect", this, index);
18186 this.fireEvent("selectionchange", this);
18190 restoreLast : function(){
18192 this.last = this._last;
18197 acceptsNav : function(row, col, cm){
18198 return !cm.isHidden(col) && cm.isCellEditable(col, row);
18202 onEditorKey : function(field, e){
18203 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18208 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18210 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18212 }else if(k == e.ENTER && !e.ctrlKey){
18216 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18218 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18220 }else if(k == e.ESC){
18224 g.startEditing(newCell[0], newCell[1]);
18229 * Ext JS Library 1.1.1
18230 * Copyright(c) 2006-2007, Ext JS, LLC.
18232 * Originally Released Under LGPL - original licence link has changed is not relivant.
18235 * <script type="text/javascript">
18239 * @class Roo.bootstrap.PagingToolbar
18241 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18243 * Create a new PagingToolbar
18244 * @param {Object} config The config object
18246 Roo.bootstrap.PagingToolbar = function(config)
18248 // old args format still supported... - xtype is prefered..
18249 // created from xtype...
18250 var ds = config.dataSource;
18251 this.toolbarItems = [];
18252 if (config.items) {
18253 this.toolbarItems = config.items;
18254 // config.items = [];
18257 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18264 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18268 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18270 * @cfg {Roo.data.Store} dataSource
18271 * The underlying data store providing the paged data
18274 * @cfg {String/HTMLElement/Element} container
18275 * container The id or element that will contain the toolbar
18278 * @cfg {Boolean} displayInfo
18279 * True to display the displayMsg (defaults to false)
18282 * @cfg {Number} pageSize
18283 * The number of records to display per page (defaults to 20)
18287 * @cfg {String} displayMsg
18288 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18290 displayMsg : 'Displaying {0} - {1} of {2}',
18292 * @cfg {String} emptyMsg
18293 * The message to display when no records are found (defaults to "No data to display")
18295 emptyMsg : 'No data to display',
18297 * Customizable piece of the default paging text (defaults to "Page")
18300 beforePageText : "Page",
18302 * Customizable piece of the default paging text (defaults to "of %0")
18305 afterPageText : "of {0}",
18307 * Customizable piece of the default paging text (defaults to "First Page")
18310 firstText : "First Page",
18312 * Customizable piece of the default paging text (defaults to "Previous Page")
18315 prevText : "Previous Page",
18317 * Customizable piece of the default paging text (defaults to "Next Page")
18320 nextText : "Next Page",
18322 * Customizable piece of the default paging text (defaults to "Last Page")
18325 lastText : "Last Page",
18327 * Customizable piece of the default paging text (defaults to "Refresh")
18330 refreshText : "Refresh",
18334 onRender : function(ct, position)
18336 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
18337 this.navgroup.parentId = this.id;
18338 this.navgroup.onRender(this.el, null);
18339 // add the buttons to the navgroup
18341 if(this.displayInfo){
18342 Roo.log(this.el.select('ul.navbar-nav',true).first());
18343 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
18344 this.displayEl = this.el.select('.x-paging-info', true).first();
18345 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
18346 // this.displayEl = navel.el.select('span',true).first();
18352 Roo.each(_this.buttons, function(e){
18353 Roo.factory(e).onRender(_this.el, null);
18357 Roo.each(_this.toolbarItems, function(e) {
18358 _this.navgroup.addItem(e);
18361 this.first = this.navgroup.addItem({
18362 tooltip: this.firstText,
18364 icon : 'fa fa-backward',
18366 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
18369 this.prev = this.navgroup.addItem({
18370 tooltip: this.prevText,
18372 icon : 'fa fa-step-backward',
18374 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
18376 //this.addSeparator();
18379 var field = this.navgroup.addItem( {
18381 cls : 'x-paging-position',
18383 html : this.beforePageText +
18384 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
18385 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
18388 this.field = field.el.select('input', true).first();
18389 this.field.on("keydown", this.onPagingKeydown, this);
18390 this.field.on("focus", function(){this.dom.select();});
18393 this.afterTextEl = field.el.select('.x-paging-after',true).first();
18394 //this.field.setHeight(18);
18395 //this.addSeparator();
18396 this.next = this.navgroup.addItem({
18397 tooltip: this.nextText,
18399 html : ' <i class="fa fa-step-forward">',
18401 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
18403 this.last = this.navgroup.addItem({
18404 tooltip: this.lastText,
18405 icon : 'fa fa-forward',
18408 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
18410 //this.addSeparator();
18411 this.loading = this.navgroup.addItem({
18412 tooltip: this.refreshText,
18413 icon: 'fa fa-refresh',
18415 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
18421 updateInfo : function(){
18422 if(this.displayEl){
18423 var count = this.ds.getCount();
18424 var msg = count == 0 ?
18428 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
18430 this.displayEl.update(msg);
18435 onLoad : function(ds, r, o){
18436 this.cursor = o.params ? o.params.start : 0;
18437 var d = this.getPageData(),
18441 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
18442 this.field.dom.value = ap;
18443 this.first.setDisabled(ap == 1);
18444 this.prev.setDisabled(ap == 1);
18445 this.next.setDisabled(ap == ps);
18446 this.last.setDisabled(ap == ps);
18447 this.loading.enable();
18452 getPageData : function(){
18453 var total = this.ds.getTotalCount();
18456 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
18457 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
18462 onLoadError : function(){
18463 this.loading.enable();
18467 onPagingKeydown : function(e){
18468 var k = e.getKey();
18469 var d = this.getPageData();
18471 var v = this.field.dom.value, pageNum;
18472 if(!v || isNaN(pageNum = parseInt(v, 10))){
18473 this.field.dom.value = d.activePage;
18476 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
18477 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
18480 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))
18482 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
18483 this.field.dom.value = pageNum;
18484 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
18487 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18489 var v = this.field.dom.value, pageNum;
18490 var increment = (e.shiftKey) ? 10 : 1;
18491 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18493 if(!v || isNaN(pageNum = parseInt(v, 10))) {
18494 this.field.dom.value = d.activePage;
18497 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
18499 this.field.dom.value = parseInt(v, 10) + increment;
18500 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
18501 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
18508 beforeLoad : function(){
18510 this.loading.disable();
18515 onClick : function(which){
18522 ds.load({params:{start: 0, limit: this.pageSize}});
18525 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
18528 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
18531 var total = ds.getTotalCount();
18532 var extra = total % this.pageSize;
18533 var lastStart = extra ? (total - extra) : total-this.pageSize;
18534 ds.load({params:{start: lastStart, limit: this.pageSize}});
18537 ds.load({params:{start: this.cursor, limit: this.pageSize}});
18543 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
18544 * @param {Roo.data.Store} store The data store to unbind
18546 unbind : function(ds){
18547 ds.un("beforeload", this.beforeLoad, this);
18548 ds.un("load", this.onLoad, this);
18549 ds.un("loadexception", this.onLoadError, this);
18550 ds.un("remove", this.updateInfo, this);
18551 ds.un("add", this.updateInfo, this);
18552 this.ds = undefined;
18556 * Binds the paging toolbar to the specified {@link Roo.data.Store}
18557 * @param {Roo.data.Store} store The data store to bind
18559 bind : function(ds){
18560 ds.on("beforeload", this.beforeLoad, this);
18561 ds.on("load", this.onLoad, this);
18562 ds.on("loadexception", this.onLoadError, this);
18563 ds.on("remove", this.updateInfo, this);
18564 ds.on("add", this.updateInfo, this);
18575 * @class Roo.bootstrap.MessageBar
18576 * @extends Roo.bootstrap.Component
18577 * Bootstrap MessageBar class
18578 * @cfg {String} html contents of the MessageBar
18579 * @cfg {String} weight (info | success | warning | danger) default info
18580 * @cfg {String} beforeClass insert the bar before the given class
18581 * @cfg {Boolean} closable (true | false) default false
18582 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
18585 * Create a new Element
18586 * @param {Object} config The config object
18589 Roo.bootstrap.MessageBar = function(config){
18590 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
18593 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
18599 beforeClass: 'bootstrap-sticky-wrap',
18601 getAutoCreate : function(){
18605 cls: 'alert alert-dismissable alert-' + this.weight,
18610 html: this.html || ''
18616 cfg.cls += ' alert-messages-fixed';
18630 onRender : function(ct, position)
18632 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
18635 var cfg = Roo.apply({}, this.getAutoCreate());
18639 cfg.cls += ' ' + this.cls;
18642 cfg.style = this.style;
18644 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
18646 this.el.setVisibilityMode(Roo.Element.DISPLAY);
18649 this.el.select('>button.close').on('click', this.hide, this);
18655 if (!this.rendered) {
18661 this.fireEvent('show', this);
18667 if (!this.rendered) {
18673 this.fireEvent('hide', this);
18676 update : function()
18678 // var e = this.el.dom.firstChild;
18680 // if(this.closable){
18681 // e = e.nextSibling;
18684 // e.data = this.html || '';
18686 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
18702 * @class Roo.bootstrap.Graph
18703 * @extends Roo.bootstrap.Component
18704 * Bootstrap Graph class
18708 @cfg {String} graphtype bar | vbar | pie
18709 @cfg {number} g_x coodinator | centre x (pie)
18710 @cfg {number} g_y coodinator | centre y (pie)
18711 @cfg {number} g_r radius (pie)
18712 @cfg {number} g_height height of the chart (respected by all elements in the set)
18713 @cfg {number} g_width width of the chart (respected by all elements in the set)
18714 @cfg {Object} title The title of the chart
18717 -opts (object) options for the chart
18719 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
18720 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
18722 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.
18723 o stacked (boolean) whether or not to tread values as in a stacked bar chart
18725 o stretch (boolean)
18727 -opts (object) options for the pie
18730 o startAngle (number)
18731 o endAngle (number)
18735 * Create a new Input
18736 * @param {Object} config The config object
18739 Roo.bootstrap.Graph = function(config){
18740 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
18746 * The img click event for the img.
18747 * @param {Roo.EventObject} e
18753 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
18764 //g_colors: this.colors,
18771 getAutoCreate : function(){
18782 onRender : function(ct,position){
18783 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
18784 this.raphael = Raphael(this.el.dom);
18786 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18787 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18788 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18789 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
18791 r.text(160, 10, "Single Series Chart").attr(txtattr);
18792 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
18793 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
18794 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
18796 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
18797 r.barchart(330, 10, 300, 220, data1);
18798 r.barchart(10, 250, 300, 220, data2, {stacked: true});
18799 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
18802 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
18803 // r.barchart(30, 30, 560, 250, xdata, {
18804 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
18805 // axis : "0 0 1 1",
18806 // axisxlabels : xdata
18807 // //yvalues : cols,
18810 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
18812 // this.load(null,xdata,{
18813 // axis : "0 0 1 1",
18814 // axisxlabels : xdata
18819 load : function(graphtype,xdata,opts){
18820 this.raphael.clear();
18822 graphtype = this.graphtype;
18827 var r = this.raphael,
18828 fin = function () {
18829 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
18831 fout = function () {
18832 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
18834 pfin = function() {
18835 this.sector.stop();
18836 this.sector.scale(1.1, 1.1, this.cx, this.cy);
18839 this.label[0].stop();
18840 this.label[0].attr({ r: 7.5 });
18841 this.label[1].attr({ "font-weight": 800 });
18844 pfout = function() {
18845 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
18848 this.label[0].animate({ r: 5 }, 500, "bounce");
18849 this.label[1].attr({ "font-weight": 400 });
18855 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
18858 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
18861 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
18862 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
18864 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
18871 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
18876 setTitle: function(o)
18881 initEvents: function() {
18884 this.el.on('click', this.onClick, this);
18888 onClick : function(e)
18890 Roo.log('img onclick');
18891 this.fireEvent('click', this, e);
18903 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
18906 * @class Roo.bootstrap.dash.NumberBox
18907 * @extends Roo.bootstrap.Component
18908 * Bootstrap NumberBox class
18909 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
18910 * @cfg {String} headline Box headline
18911 * @cfg {String} content Box content
18912 * @cfg {String} icon Box icon
18913 * @cfg {String} footer Footer text
18914 * @cfg {String} fhref Footer href
18917 * Create a new NumberBox
18918 * @param {Object} config The config object
18922 Roo.bootstrap.dash.NumberBox = function(config){
18923 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
18927 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
18937 getAutoCreate : function(){
18941 cls : 'small-box bg-' + this.bgcolor,
18949 cls : 'roo-headline',
18950 html : this.headline
18954 cls : 'roo-content',
18955 html : this.content
18969 cls : 'ion ' + this.icon
18978 cls : 'small-box-footer',
18979 href : this.fhref || '#',
18983 cfg.cn.push(footer);
18990 onRender : function(ct,position){
18991 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
18998 setHeadline: function (value)
19000 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19003 setFooter: function (value, href)
19005 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19008 this.el.select('a.small-box-footer',true).first().attr('href', href);
19013 setContent: function (value)
19015 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19018 initEvents: function()
19032 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19035 * @class Roo.bootstrap.dash.TabBox
19036 * @extends Roo.bootstrap.Component
19037 * Bootstrap TabBox class
19038 * @cfg {String} title Title of the TabBox
19039 * @cfg {String} icon Icon of the TabBox
19042 * Create a new TabBox
19043 * @param {Object} config The config object
19047 Roo.bootstrap.dash.TabBox = function(config){
19048 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19052 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19057 getChildContainer : function()
19059 return this.el.select('.tab-content', true).first();
19062 getAutoCreate : function(){
19066 cls: 'pull-left header',
19074 cls: 'fa ' + this.icon
19081 cls: 'nav-tabs-custom',
19085 cls: 'nav nav-tabs pull-right',
19092 cls: 'tab-content no-padding',
19101 setTitle : function(value)
19103 this.el.select('.header', true).first().dom.innerHTML = value;
19115 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19117 * @class Roo.bootstrap.TabPane
19118 * @extends Roo.bootstrap.Component
19119 * Bootstrap TabPane class
19120 * @cfg {Boolean} active (false | true) Default false
19124 * Create a new TabPane
19125 * @param {Object} config The config object
19128 Roo.bootstrap.dash.TabPane = function(config){
19129 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19133 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
19137 // getBox : function()
19139 // return this.el.findParent('.nav-tabs-custom', false, true);
19142 getAutoCreate : function()
19150 cfg.cls += ' active';
19168 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19171 * @class Roo.bootstrap.menu.Menu
19172 * @extends Roo.bootstrap.Component
19173 * Bootstrap Menu class - container for Menu
19174 * @cfg {String} html Text of the menu
19175 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19176 * @cfg {String} icon Font awesome icon
19177 * @cfg {String} pos Menu align to (top | bottom) default bottom
19181 * Create a new Menu
19182 * @param {Object} config The config object
19186 Roo.bootstrap.menu.Menu = function(config){
19187 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19191 * @event beforeshow
19192 * Fires before this menu is displayed
19193 * @param {Roo.bootstrap.menu.Menu} this
19197 * @event beforehide
19198 * Fires before this menu is hidden
19199 * @param {Roo.bootstrap.menu.Menu} this
19204 * Fires after this menu is displayed
19205 * @param {Roo.bootstrap.menu.Menu} this
19210 * Fires after this menu is hidden
19211 * @param {Roo.bootstrap.menu.Menu} this
19216 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19217 * @param {Roo.bootstrap.menu.Menu} this
19218 * @param {Roo.EventObject} e
19225 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
19229 weight : 'default',
19234 getChildContainer : function() {
19235 if(this.isSubMenu){
19239 return this.el.select('ul.dropdown-menu', true).first();
19242 getAutoCreate : function()
19247 cls : 'roo-menu-text',
19255 cls : 'fa ' + this.icon
19266 cls : 'dropdown-button btn btn-' + this.weight,
19271 cls : 'dropdown-toggle btn btn-' + this.weight,
19281 cls : 'dropdown-menu'
19287 if(this.pos == 'top'){
19288 cfg.cls += ' dropup';
19291 if(this.isSubMenu){
19294 cls : 'dropdown-menu'
19301 onRender : function(ct, position)
19303 this.isSubMenu = ct.hasClass('dropdown-submenu');
19305 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
19308 initEvents : function()
19310 if(this.isSubMenu){
19314 this.hidden = true;
19316 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
19317 this.triggerEl.on('click', this.onTriggerPress, this);
19319 this.buttonEl = this.el.select('button.dropdown-button', true).first();
19320 this.buttonEl.on('click', this.onClick, this);
19326 if(this.isSubMenu){
19330 return this.el.select('ul.dropdown-menu', true).first();
19333 onClick : function(e)
19335 this.fireEvent("click", this, e);
19338 onTriggerPress : function(e)
19340 if (this.isVisible()) {
19347 isVisible : function(){
19348 return !this.hidden;
19353 this.fireEvent("beforeshow", this);
19355 this.hidden = false;
19356 this.el.addClass('open');
19358 Roo.get(document).on("mouseup", this.onMouseUp, this);
19360 this.fireEvent("show", this);
19367 this.fireEvent("beforehide", this);
19369 this.hidden = true;
19370 this.el.removeClass('open');
19372 Roo.get(document).un("mouseup", this.onMouseUp);
19374 this.fireEvent("hide", this);
19377 onMouseUp : function()
19391 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19394 * @class Roo.bootstrap.menu.Item
19395 * @extends Roo.bootstrap.Component
19396 * Bootstrap MenuItem class
19397 * @cfg {Boolean} submenu (true | false) default false
19398 * @cfg {String} html text of the item
19399 * @cfg {String} href the link
19400 * @cfg {Boolean} disable (true | false) default false
19401 * @cfg {Boolean} preventDefault (true | false) default true
19402 * @cfg {String} icon Font awesome icon
19403 * @cfg {String} pos Submenu align to (left | right) default right
19407 * Create a new Item
19408 * @param {Object} config The config object
19412 Roo.bootstrap.menu.Item = function(config){
19413 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
19417 * Fires when the mouse is hovering over this menu
19418 * @param {Roo.bootstrap.menu.Item} this
19419 * @param {Roo.EventObject} e
19424 * Fires when the mouse exits this menu
19425 * @param {Roo.bootstrap.menu.Item} this
19426 * @param {Roo.EventObject} e
19432 * The raw click event for the entire grid.
19433 * @param {Roo.EventObject} e
19439 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
19444 preventDefault: true,
19449 getAutoCreate : function()
19454 cls : 'roo-menu-item-text',
19462 cls : 'fa ' + this.icon
19471 href : this.href || '#',
19478 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
19482 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
19484 if(this.pos == 'left'){
19485 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
19492 initEvents : function()
19494 this.el.on('mouseover', this.onMouseOver, this);
19495 this.el.on('mouseout', this.onMouseOut, this);
19497 this.el.select('a', true).first().on('click', this.onClick, this);
19501 onClick : function(e)
19503 if(this.preventDefault){
19504 e.preventDefault();
19507 this.fireEvent("click", this, e);
19510 onMouseOver : function(e)
19512 if(this.submenu && this.pos == 'left'){
19513 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
19516 this.fireEvent("mouseover", this, e);
19519 onMouseOut : function(e)
19521 this.fireEvent("mouseout", this, e);
19533 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19536 * @class Roo.bootstrap.menu.Separator
19537 * @extends Roo.bootstrap.Component
19538 * Bootstrap Separator class
19541 * Create a new Separator
19542 * @param {Object} config The config object
19546 Roo.bootstrap.menu.Separator = function(config){
19547 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
19550 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
19552 getAutoCreate : function(){