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';
972 * @class Roo.bootstrap.Img
973 * @extends Roo.bootstrap.Component
974 * Bootstrap Img class
975 * @cfg {Boolean} imgResponsive false | true
976 * @cfg {String} border rounded | circle | thumbnail
977 * @cfg {String} src image source
978 * @cfg {String} alt image alternative text
979 * @cfg {String} href a tag href
980 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
984 * @param {Object} config The config object
987 Roo.bootstrap.Img = function(config){
988 Roo.bootstrap.Img.superclass.constructor.call(this, config);
994 * The img click event for the img.
995 * @param {Roo.EventObject} e
1001 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1003 imgResponsive: true,
1009 getAutoCreate : function(){
1013 cls: (this.imgResponsive) ? 'img-responsive' : '',
1017 cfg.html = this.html || cfg.html;
1019 cfg.src = this.src || cfg.src;
1021 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1022 cfg.cls += ' img-' + this.border;
1039 a.target = this.target;
1045 return (this.href) ? a : cfg;
1048 initEvents: function() {
1051 this.el.on('click', this.onClick, this);
1055 onClick : function(e)
1057 Roo.log('img onclick');
1058 this.fireEvent('click', this, e);
1072 * @class Roo.bootstrap.Link
1073 * @extends Roo.bootstrap.Component
1074 * Bootstrap Link Class
1075 * @cfg {String} alt image alternative text
1076 * @cfg {String} href a tag href
1077 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1078 * @cfg {String} html the content of the link.
1082 * Create a new Input
1083 * @param {Object} config The config object
1086 Roo.bootstrap.Link = function(config){
1087 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1093 * The img click event for the img.
1094 * @param {Roo.EventObject} e
1100 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1105 getAutoCreate : function(){
1109 html : this.html || 'html-missing'
1116 cfg.href = this.href || '#';
1118 cfg.target = this.target;
1124 initEvents: function() {
1127 this.el.on('click', this.onClick, this);
1131 onClick : function(e)
1133 //Roo.log('img onclick');
1134 this.fireEvent('click', this, e);
1147 * @class Roo.bootstrap.Header
1148 * @extends Roo.bootstrap.Component
1149 * Bootstrap Header class
1150 * @cfg {String} html content of header
1151 * @cfg {Number} level (1|2|3|4|5|6) default 1
1154 * Create a new Header
1155 * @param {Object} config The config object
1159 Roo.bootstrap.Header = function(config){
1160 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1163 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1171 getAutoCreate : function(){
1174 tag: 'h' + (1 *this.level),
1175 html: this.html || 'fill in html'
1187 * Ext JS Library 1.1.1
1188 * Copyright(c) 2006-2007, Ext JS, LLC.
1190 * Originally Released Under LGPL - original licence link has changed is not relivant.
1193 * <script type="text/javascript">
1197 * @class Roo.bootstrap.MenuMgr
1198 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1201 Roo.bootstrap.MenuMgr = function(){
1202 var menus, active, groups = {}, attached = false, lastShow = new Date();
1204 // private - called when first menu is created
1207 active = new Roo.util.MixedCollection();
1208 Roo.get(document).addKeyListener(27, function(){
1209 if(active.length > 0){
1217 if(active && active.length > 0){
1218 var c = active.clone();
1228 if(active.length < 1){
1229 Roo.get(document).un("mouseup", onMouseDown);
1237 var last = active.last();
1238 lastShow = new Date();
1241 Roo.get(document).on("mouseup", onMouseDown);
1246 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1247 m.parentMenu.activeChild = m;
1248 }else if(last && last.isVisible()){
1249 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1254 function onBeforeHide(m){
1256 m.activeChild.hide();
1258 if(m.autoHideTimer){
1259 clearTimeout(m.autoHideTimer);
1260 delete m.autoHideTimer;
1265 function onBeforeShow(m){
1266 var pm = m.parentMenu;
1267 if(!pm && !m.allowOtherMenus){
1269 }else if(pm && pm.activeChild && active != m){
1270 pm.activeChild.hide();
1275 function onMouseDown(e){
1276 Roo.log("on MouseDown");
1277 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1285 function onBeforeCheck(mi, state){
1287 var g = groups[mi.group];
1288 for(var i = 0, l = g.length; i < l; i++){
1290 g[i].setChecked(false);
1299 * Hides all menus that are currently visible
1301 hideAll : function(){
1306 register : function(menu){
1310 menus[menu.id] = menu;
1311 menu.on("beforehide", onBeforeHide);
1312 menu.on("hide", onHide);
1313 menu.on("beforeshow", onBeforeShow);
1314 menu.on("show", onShow);
1316 if(g && menu.events["checkchange"]){
1320 groups[g].push(menu);
1321 menu.on("checkchange", onCheck);
1326 * Returns a {@link Roo.menu.Menu} object
1327 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1328 * be used to generate and return a new Menu instance.
1330 get : function(menu){
1331 if(typeof menu == "string"){ // menu id
1333 }else if(menu.events){ // menu instance
1336 /*else if(typeof menu.length == 'number'){ // array of menu items?
1337 return new Roo.bootstrap.Menu({items:menu});
1338 }else{ // otherwise, must be a config
1339 return new Roo.bootstrap.Menu(menu);
1346 unregister : function(menu){
1347 delete menus[menu.id];
1348 menu.un("beforehide", onBeforeHide);
1349 menu.un("hide", onHide);
1350 menu.un("beforeshow", onBeforeShow);
1351 menu.un("show", onShow);
1353 if(g && menu.events["checkchange"]){
1354 groups[g].remove(menu);
1355 menu.un("checkchange", onCheck);
1360 registerCheckable : function(menuItem){
1361 var g = menuItem.group;
1366 groups[g].push(menuItem);
1367 menuItem.on("beforecheckchange", onBeforeCheck);
1372 unregisterCheckable : function(menuItem){
1373 var g = menuItem.group;
1375 groups[g].remove(menuItem);
1376 menuItem.un("beforecheckchange", onBeforeCheck);
1388 * @class Roo.bootstrap.Menu
1389 * @extends Roo.bootstrap.Component
1390 * Bootstrap Menu class - container for MenuItems
1391 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1395 * @param {Object} config The config object
1399 Roo.bootstrap.Menu = function(config){
1400 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1401 if (this.registerMenu) {
1402 Roo.bootstrap.MenuMgr.register(this);
1407 * Fires before this menu is displayed
1408 * @param {Roo.menu.Menu} this
1413 * Fires before this menu is hidden
1414 * @param {Roo.menu.Menu} this
1419 * Fires after this menu is displayed
1420 * @param {Roo.menu.Menu} this
1425 * Fires after this menu is hidden
1426 * @param {Roo.menu.Menu} this
1431 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1432 * @param {Roo.menu.Menu} this
1433 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1434 * @param {Roo.EventObject} e
1439 * Fires when the mouse is hovering over this menu
1440 * @param {Roo.menu.Menu} this
1441 * @param {Roo.EventObject} e
1442 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1447 * Fires when the mouse exits this menu
1448 * @param {Roo.menu.Menu} this
1449 * @param {Roo.EventObject} e
1450 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1455 * Fires when a menu item contained in this menu is clicked
1456 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1457 * @param {Roo.EventObject} e
1461 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1464 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1468 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1471 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1473 registerMenu : true,
1475 menuItems :false, // stores the menu items..
1481 getChildContainer : function() {
1485 getAutoCreate : function(){
1487 //if (['right'].indexOf(this.align)!==-1) {
1488 // cfg.cn[1].cls += ' pull-right'
1494 cls : 'dropdown-menu' ,
1495 style : 'z-index:1000'
1499 if (this.type === 'submenu') {
1500 cfg.cls = 'submenu active';
1502 if (this.type === 'treeview') {
1503 cfg.cls = 'treeview-menu';
1508 initEvents : function() {
1510 // Roo.log("ADD event");
1511 // Roo.log(this.triggerEl.dom);
1512 this.triggerEl.on('click', this.onTriggerPress, this);
1513 this.triggerEl.addClass('dropdown-toggle');
1514 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1516 this.el.on("mouseover", this.onMouseOver, this);
1517 this.el.on("mouseout", this.onMouseOut, this);
1521 findTargetItem : function(e){
1522 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1526 //Roo.log(t); Roo.log(t.id);
1528 //Roo.log(this.menuitems);
1529 return this.menuitems.get(t.id);
1531 //return this.items.get(t.menuItemId);
1536 onClick : function(e){
1537 Roo.log("menu.onClick");
1538 var t = this.findTargetItem(e);
1544 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1545 if(t == this.activeItem && t.shouldDeactivate(e)){
1546 this.activeItem.deactivate();
1547 delete this.activeItem;
1551 this.setActiveItem(t, true);
1558 Roo.log('pass click event');
1562 this.fireEvent("click", this, t, e);
1566 onMouseOver : function(e){
1567 var t = this.findTargetItem(e);
1570 // if(t.canActivate && !t.disabled){
1571 // this.setActiveItem(t, true);
1575 this.fireEvent("mouseover", this, e, t);
1577 isVisible : function(){
1578 return !this.hidden;
1580 onMouseOut : function(e){
1581 var t = this.findTargetItem(e);
1584 // if(t == this.activeItem && t.shouldDeactivate(e)){
1585 // this.activeItem.deactivate();
1586 // delete this.activeItem;
1589 this.fireEvent("mouseout", this, e, t);
1594 * Displays this menu relative to another element
1595 * @param {String/HTMLElement/Roo.Element} element The element to align to
1596 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1597 * the element (defaults to this.defaultAlign)
1598 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1600 show : function(el, pos, parentMenu){
1601 this.parentMenu = parentMenu;
1605 this.fireEvent("beforeshow", this);
1606 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1609 * Displays this menu at a specific xy position
1610 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1611 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1613 showAt : function(xy, parentMenu, /* private: */_e){
1614 this.parentMenu = parentMenu;
1619 this.fireEvent("beforeshow", this);
1621 //xy = this.el.adjustForConstraints(xy);
1623 //this.el.setXY(xy);
1625 this.hideMenuItems();
1626 this.hidden = false;
1627 this.triggerEl.addClass('open');
1629 this.fireEvent("show", this);
1635 this.doFocus.defer(50, this);
1639 doFocus : function(){
1641 this.focusEl.focus();
1646 * Hides this menu and optionally all parent menus
1647 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1649 hide : function(deep){
1651 this.hideMenuItems();
1652 if(this.el && this.isVisible()){
1653 this.fireEvent("beforehide", this);
1654 if(this.activeItem){
1655 this.activeItem.deactivate();
1656 this.activeItem = null;
1658 this.triggerEl.removeClass('open');;
1660 this.fireEvent("hide", this);
1662 if(deep === true && this.parentMenu){
1663 this.parentMenu.hide(true);
1667 onTriggerPress : function(e)
1670 Roo.log('trigger press');
1671 //Roo.log(e.getTarget());
1672 // Roo.log(this.triggerEl.dom);
1673 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1676 if (this.isVisible()) {
1680 this.show(this.triggerEl, false, false);
1689 hideMenuItems : function()
1691 //$(backdrop).remove()
1692 Roo.select('.open',true).each(function(aa) {
1694 aa.removeClass('open');
1695 //var parent = getParent($(this))
1696 //var relatedTarget = { relatedTarget: this }
1698 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1699 //if (e.isDefaultPrevented()) return
1700 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1703 addxtypeChild : function (tree, cntr) {
1704 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1706 this.menuitems.add(comp);
1727 * @class Roo.bootstrap.MenuItem
1728 * @extends Roo.bootstrap.Component
1729 * Bootstrap MenuItem class
1730 * @cfg {String} html the menu label
1731 * @cfg {String} href the link
1732 * @cfg {Boolean} preventDefault (true | false) default true
1736 * Create a new MenuItem
1737 * @param {Object} config The config object
1741 Roo.bootstrap.MenuItem = function(config){
1742 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1747 * The raw click event for the entire grid.
1748 * @param {Roo.EventObject} e
1754 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1758 preventDefault: true,
1760 getAutoCreate : function(){
1763 cls: 'dropdown-menu-item',
1772 if (this.parent().type == 'treeview') {
1773 cfg.cls = 'treeview-menu';
1776 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1777 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1781 initEvents: function() {
1783 //this.el.select('a').on('click', this.onClick, this);
1786 onClick : function(e)
1788 Roo.log('item on click ');
1789 //if(this.preventDefault){
1790 // e.preventDefault();
1792 //this.parent().hideMenuItems();
1794 this.fireEvent('click', this, e);
1813 * @class Roo.bootstrap.MenuSeparator
1814 * @extends Roo.bootstrap.Component
1815 * Bootstrap MenuSeparator class
1818 * Create a new MenuItem
1819 * @param {Object} config The config object
1823 Roo.bootstrap.MenuSeparator = function(config){
1824 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1827 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1829 getAutoCreate : function(){
1844 <div class="modal fade">
1845 <div class="modal-dialog">
1846 <div class="modal-content">
1847 <div class="modal-header">
1848 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1849 <h4 class="modal-title">Modal title</h4>
1851 <div class="modal-body">
1852 <p>One fine body…</p>
1854 <div class="modal-footer">
1855 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1856 <button type="button" class="btn btn-primary">Save changes</button>
1858 </div><!-- /.modal-content -->
1859 </div><!-- /.modal-dialog -->
1860 </div><!-- /.modal -->
1870 * @class Roo.bootstrap.Modal
1871 * @extends Roo.bootstrap.Component
1872 * Bootstrap Modal class
1873 * @cfg {String} title Title of dialog
1874 * @cfg {Boolean} specificTitle (true|false) default false
1875 * @cfg {Array} buttons Array of buttons or standard button set..
1876 * @cfg {String} buttonPosition (left|right|center) default right
1879 * Create a new Modal Dialog
1880 * @param {Object} config The config object
1883 Roo.bootstrap.Modal = function(config){
1884 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1889 * The raw btnclick event for the button
1890 * @param {Roo.EventObject} e
1894 this.buttons = this.buttons || [];
1897 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1899 title : 'test dialog',
1906 specificTitle: false,
1908 buttonPosition: 'right',
1910 onRender : function(ct, position)
1912 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1915 var cfg = Roo.apply({}, this.getAutoCreate());
1918 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1920 //if (!cfg.name.length) {
1924 cfg.cls += ' ' + this.cls;
1927 cfg.style = this.style;
1929 this.el = Roo.get(document.body).createChild(cfg, position);
1931 //var type = this.el.dom.type;
1933 if(this.tabIndex !== undefined){
1934 this.el.dom.setAttribute('tabIndex', this.tabIndex);
1939 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1940 this.maskEl.enableDisplayMode("block");
1942 //this.el.addClass("x-dlg-modal");
1944 if (this.buttons.length) {
1945 Roo.each(this.buttons, function(bb) {
1946 b = Roo.apply({}, bb);
1947 b.xns = b.xns || Roo.bootstrap;
1948 b.xtype = b.xtype || 'Button';
1949 if (typeof(b.listeners) == 'undefined') {
1950 b.listeners = { click : this.onButtonClick.createDelegate(this) };
1953 var btn = Roo.factory(b);
1955 btn.onRender(this.el.select('.modal-footer div').first());
1959 // render the children.
1962 if(typeof(this.items) != 'undefined'){
1963 var items = this.items;
1966 for(var i =0;i < items.length;i++) {
1967 nitems.push(this.addxtype(Roo.apply({}, items[i])));
1971 this.items = nitems;
1973 this.body = this.el.select('.modal-body',true).first();
1974 this.close = this.el.select('.modal-header .close', true).first();
1975 this.footer = this.el.select('.modal-footer',true).first();
1977 //this.el.addClass([this.fieldClass, this.cls]);
1980 getAutoCreate : function(){
1985 html : this.html || ''
1990 cls : 'modal-title',
1994 if(this.specificTitle){
2000 style : 'display: none',
2003 cls: "modal-dialog",
2006 cls : "modal-content",
2009 cls : 'modal-header',
2021 cls : 'modal-footer',
2025 cls: 'btn-' + this.buttonPosition
2044 getChildContainer : function() {
2046 return this.el.select('.modal-body',true).first();
2049 getButtonContainer : function() {
2050 return this.el.select('.modal-footer div',true).first();
2053 initEvents : function()
2055 this.el.select('.modal-header .close').on('click', this.hide, this);
2057 // this.addxtype(this);
2061 if (!this.rendered) {
2065 this.el.addClass('on');
2066 this.el.removeClass('fade');
2067 this.el.setStyle('display', 'block');
2068 Roo.get(document.body).addClass("x-body-masked");
2069 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2071 this.el.setStyle('zIndex', '10001');
2072 this.fireEvent('show', this);
2078 Roo.log('Modal hide?!');
2080 Roo.get(document.body).removeClass("x-body-masked");
2081 this.el.removeClass('on');
2082 this.el.addClass('fade');
2083 this.el.setStyle('display', 'none');
2084 this.fireEvent('hide', this);
2087 addButton : function(str, cb)
2091 var b = Roo.apply({}, { html : str } );
2092 b.xns = b.xns || Roo.bootstrap;
2093 b.xtype = b.xtype || 'Button';
2094 if (typeof(b.listeners) == 'undefined') {
2095 b.listeners = { click : cb.createDelegate(this) };
2098 var btn = Roo.factory(b);
2100 btn.onRender(this.el.select('.modal-footer div').first());
2106 setDefaultButton : function(btn)
2108 //this.el.select('.modal-footer').()
2110 resizeTo: function(w,h)
2114 setContentSize : function(w, h)
2118 onButtonClick: function(btn,e)
2121 this.fireEvent('btnclick', btn.name, e);
2123 setTitle: function(str) {
2124 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2130 Roo.apply(Roo.bootstrap.Modal, {
2132 * Button config that displays a single OK button
2141 * Button config that displays Yes and No buttons
2157 * Button config that displays OK and Cancel buttons
2172 * Button config that displays Yes, No and Cancel buttons
2194 * messagebox - can be used as a replace
2198 * @class Roo.MessageBox
2199 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2203 Roo.Msg.alert('Status', 'Changes saved successfully.');
2205 // Prompt for user data:
2206 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2208 // process text value...
2212 // Show a dialog using config options:
2214 title:'Save Changes?',
2215 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2216 buttons: Roo.Msg.YESNOCANCEL,
2223 Roo.bootstrap.MessageBox = function(){
2224 var dlg, opt, mask, waitTimer;
2225 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2226 var buttons, activeTextEl, bwidth;
2230 var handleButton = function(button){
2232 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2236 var handleHide = function(){
2238 dlg.el.removeClass(opt.cls);
2241 // Roo.TaskMgr.stop(waitTimer);
2242 // waitTimer = null;
2247 var updateButtons = function(b){
2250 buttons["ok"].hide();
2251 buttons["cancel"].hide();
2252 buttons["yes"].hide();
2253 buttons["no"].hide();
2254 //dlg.footer.dom.style.display = 'none';
2257 dlg.footer.dom.style.display = '';
2258 for(var k in buttons){
2259 if(typeof buttons[k] != "function"){
2262 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2263 width += buttons[k].el.getWidth()+15;
2273 var handleEsc = function(d, k, e){
2274 if(opt && opt.closable !== false){
2284 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2285 * @return {Roo.BasicDialog} The BasicDialog element
2287 getDialog : function(){
2289 dlg = new Roo.bootstrap.Modal( {
2292 //constraintoviewport:false,
2294 //collapsible : false,
2299 //buttonAlign:"center",
2300 closeClick : function(){
2301 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2304 handleButton("cancel");
2309 dlg.on("hide", handleHide);
2311 //dlg.addKeyListener(27, handleEsc);
2313 this.buttons = buttons;
2314 var bt = this.buttonText;
2315 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2316 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2317 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2318 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2320 bodyEl = dlg.body.createChild({
2322 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2323 '<textarea class="roo-mb-textarea"></textarea>' +
2324 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2326 msgEl = bodyEl.dom.firstChild;
2327 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2328 textboxEl.enableDisplayMode();
2329 textboxEl.addKeyListener([10,13], function(){
2330 if(dlg.isVisible() && opt && opt.buttons){
2333 }else if(opt.buttons.yes){
2334 handleButton("yes");
2338 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2339 textareaEl.enableDisplayMode();
2340 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2341 progressEl.enableDisplayMode();
2342 var pf = progressEl.dom.firstChild;
2344 pp = Roo.get(pf.firstChild);
2345 pp.setHeight(pf.offsetHeight);
2353 * Updates the message box body text
2354 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2355 * the XHTML-compliant non-breaking space character '&#160;')
2356 * @return {Roo.MessageBox} This message box
2358 updateText : function(text){
2359 if(!dlg.isVisible() && !opt.width){
2360 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2362 msgEl.innerHTML = text || ' ';
2364 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2365 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2367 Math.min(opt.width || cw , this.maxWidth),
2368 Math.max(opt.minWidth || this.minWidth, bwidth)
2371 activeTextEl.setWidth(w);
2373 if(dlg.isVisible()){
2374 dlg.fixedcenter = false;
2376 // to big, make it scroll. = But as usual stupid IE does not support
2379 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2380 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2381 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2383 bodyEl.dom.style.height = '';
2384 bodyEl.dom.style.overflowY = '';
2387 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2389 bodyEl.dom.style.overflowX = '';
2392 dlg.setContentSize(w, bodyEl.getHeight());
2393 if(dlg.isVisible()){
2394 dlg.fixedcenter = true;
2400 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2401 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2402 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2403 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2404 * @return {Roo.MessageBox} This message box
2406 updateProgress : function(value, text){
2408 this.updateText(text);
2410 if (pp) { // weird bug on my firefox - for some reason this is not defined
2411 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2417 * Returns true if the message box is currently displayed
2418 * @return {Boolean} True if the message box is visible, else false
2420 isVisible : function(){
2421 return dlg && dlg.isVisible();
2425 * Hides the message box if it is displayed
2428 if(this.isVisible()){
2434 * Displays a new message box, or reinitializes an existing message box, based on the config options
2435 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2436 * The following config object properties are supported:
2438 Property Type Description
2439 ---------- --------------- ------------------------------------------------------------------------------------
2440 animEl String/Element An id or Element from which the message box should animate as it opens and
2441 closes (defaults to undefined)
2442 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2443 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2444 closable Boolean False to hide the top-right close button (defaults to true). Note that
2445 progress and wait dialogs will ignore this property and always hide the
2446 close button as they can only be closed programmatically.
2447 cls String A custom CSS class to apply to the message box element
2448 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2449 displayed (defaults to 75)
2450 fn Function A callback function to execute after closing the dialog. The arguments to the
2451 function will be btn (the name of the button that was clicked, if applicable,
2452 e.g. "ok"), and text (the value of the active text field, if applicable).
2453 Progress and wait dialogs will ignore this option since they do not respond to
2454 user actions and can only be closed programmatically, so any required function
2455 should be called by the same code after it closes the dialog.
2456 icon String A CSS class that provides a background image to be used as an icon for
2457 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2458 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2459 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2460 modal Boolean False to allow user interaction with the page while the message box is
2461 displayed (defaults to true)
2462 msg String A string that will replace the existing message box body text (defaults
2463 to the XHTML-compliant non-breaking space character ' ')
2464 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2465 progress Boolean True to display a progress bar (defaults to false)
2466 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2467 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2468 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2469 title String The title text
2470 value String The string value to set into the active textbox element if displayed
2471 wait Boolean True to display a progress bar (defaults to false)
2472 width Number The width of the dialog in pixels
2479 msg: 'Please enter your address:',
2481 buttons: Roo.MessageBox.OKCANCEL,
2484 animEl: 'addAddressBtn'
2487 * @param {Object} config Configuration options
2488 * @return {Roo.MessageBox} This message box
2490 show : function(options)
2493 // this causes nightmares if you show one dialog after another
2494 // especially on callbacks..
2496 if(this.isVisible()){
2499 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2500 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2501 Roo.log("New Dialog Message:" + options.msg )
2502 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2503 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2506 var d = this.getDialog();
2508 d.setTitle(opt.title || " ");
2509 d.close.setDisplayed(opt.closable !== false);
2510 activeTextEl = textboxEl;
2511 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2516 textareaEl.setHeight(typeof opt.multiline == "number" ?
2517 opt.multiline : this.defaultTextHeight);
2518 activeTextEl = textareaEl;
2527 progressEl.setDisplayed(opt.progress === true);
2528 this.updateProgress(0);
2529 activeTextEl.dom.value = opt.value || "";
2531 dlg.setDefaultButton(activeTextEl);
2533 var bs = opt.buttons;
2537 }else if(bs && bs.yes){
2538 db = buttons["yes"];
2540 dlg.setDefaultButton(db);
2542 bwidth = updateButtons(opt.buttons);
2543 this.updateText(opt.msg);
2545 d.el.addClass(opt.cls);
2547 d.proxyDrag = opt.proxyDrag === true;
2548 d.modal = opt.modal !== false;
2549 d.mask = opt.modal !== false ? mask : false;
2551 // force it to the end of the z-index stack so it gets a cursor in FF
2552 document.body.appendChild(dlg.el.dom);
2553 d.animateTarget = null;
2554 d.show(options.animEl);
2560 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2561 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2562 * and closing the message box when the process is complete.
2563 * @param {String} title The title bar text
2564 * @param {String} msg The message box body text
2565 * @return {Roo.MessageBox} This message box
2567 progress : function(title, msg){
2574 minWidth: this.minProgressWidth,
2581 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2582 * If a callback function is passed it will be called after the user clicks the button, and the
2583 * id of the button that was clicked will be passed as the only parameter to the callback
2584 * (could also be the top-right close button).
2585 * @param {String} title The title bar text
2586 * @param {String} msg The message box body text
2587 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2588 * @param {Object} scope (optional) The scope of the callback function
2589 * @return {Roo.MessageBox} This message box
2591 alert : function(title, msg, fn, scope){
2604 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2605 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2606 * You are responsible for closing the message box when the process is complete.
2607 * @param {String} msg The message box body text
2608 * @param {String} title (optional) The title bar text
2609 * @return {Roo.MessageBox} This message box
2611 wait : function(msg, title){
2622 waitTimer = Roo.TaskMgr.start({
2624 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2632 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2633 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2634 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2635 * @param {String} title The title bar text
2636 * @param {String} msg The message box body text
2637 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2638 * @param {Object} scope (optional) The scope of the callback function
2639 * @return {Roo.MessageBox} This message box
2641 confirm : function(title, msg, fn, scope){
2645 buttons: this.YESNO,
2654 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2655 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2656 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2657 * (could also be the top-right close button) and the text that was entered will be passed as the two
2658 * parameters to the callback.
2659 * @param {String} title The title bar text
2660 * @param {String} msg The message box body text
2661 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2662 * @param {Object} scope (optional) The scope of the callback function
2663 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2664 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2665 * @return {Roo.MessageBox} This message box
2667 prompt : function(title, msg, fn, scope, multiline){
2671 buttons: this.OKCANCEL,
2676 multiline: multiline,
2683 * Button config that displays a single OK button
2688 * Button config that displays Yes and No buttons
2691 YESNO : {yes:true, no:true},
2693 * Button config that displays OK and Cancel buttons
2696 OKCANCEL : {ok:true, cancel:true},
2698 * Button config that displays Yes, No and Cancel buttons
2701 YESNOCANCEL : {yes:true, no:true, cancel:true},
2704 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2707 defaultTextHeight : 75,
2709 * The maximum width in pixels of the message box (defaults to 600)
2714 * The minimum width in pixels of the message box (defaults to 100)
2719 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2720 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2723 minProgressWidth : 250,
2725 * An object containing the default button text strings that can be overriden for localized language support.
2726 * Supported properties are: ok, cancel, yes and no.
2727 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2740 * Shorthand for {@link Roo.MessageBox}
2742 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2743 Roo.Msg = Roo.Msg || Roo.MessageBox;
2752 * @class Roo.bootstrap.Navbar
2753 * @extends Roo.bootstrap.Component
2754 * Bootstrap Navbar class
2757 * Create a new Navbar
2758 * @param {Object} config The config object
2762 Roo.bootstrap.Navbar = function(config){
2763 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2767 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2776 getAutoCreate : function(){
2779 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
2783 initEvents :function ()
2785 //Roo.log(this.el.select('.navbar-toggle',true));
2786 this.el.select('.navbar-toggle',true).on('click', function() {
2787 // Roo.log('click');
2788 this.el.select('.navbar-collapse',true).toggleClass('in');
2796 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2798 var size = this.el.getSize();
2799 this.maskEl.setSize(size.width, size.height);
2800 this.maskEl.enableDisplayMode("block");
2809 getChildContainer : function()
2811 if (this.el.select('.collapse').getCount()) {
2812 return this.el.select('.collapse',true).first();
2845 * @class Roo.bootstrap.NavSimplebar
2846 * @extends Roo.bootstrap.Navbar
2847 * Bootstrap Sidebar class
2849 * @cfg {Boolean} inverse is inverted color
2851 * @cfg {String} type (nav | pills | tabs)
2852 * @cfg {Boolean} arrangement stacked | justified
2853 * @cfg {String} align (left | right) alignment
2855 * @cfg {Boolean} main (true|false) main nav bar? default false
2856 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
2858 * @cfg {String} tag (header|footer|nav|div) default is nav
2864 * Create a new Sidebar
2865 * @param {Object} config The config object
2869 Roo.bootstrap.NavSimplebar = function(config){
2870 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
2873 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
2889 getAutoCreate : function(){
2893 tag : this.tag || 'div',
2906 this.type = this.type || 'nav';
2907 if (['tabs','pills'].indexOf(this.type)!==-1) {
2908 cfg.cn[0].cls += ' nav-' + this.type
2912 if (this.type!=='nav') {
2913 Roo.log('nav type must be nav/tabs/pills')
2915 cfg.cn[0].cls += ' navbar-nav'
2921 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
2922 cfg.cn[0].cls += ' nav-' + this.arrangement;
2926 if (this.align === 'right') {
2927 cfg.cn[0].cls += ' navbar-right';
2931 cfg.cls += ' navbar-inverse';
2958 * @class Roo.bootstrap.NavHeaderbar
2959 * @extends Roo.bootstrap.NavSimplebar
2960 * Bootstrap Sidebar class
2962 * @cfg {String} brand what is brand
2963 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
2964 * @cfg {String} brand_href href of the brand
2967 * Create a new Sidebar
2968 * @param {Object} config The config object
2972 Roo.bootstrap.NavHeaderbar = function(config){
2973 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
2976 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
2983 getAutoCreate : function(){
2988 tag: this.nav || 'nav',
2994 cls: 'navbar-header',
2999 cls: 'navbar-toggle',
3000 'data-toggle': 'collapse',
3005 html: 'Toggle navigation'
3025 cls: 'collapse navbar-collapse'
3030 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3032 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3033 cfg.cls += ' navbar-' + this.position;
3035 // tag can override this..
3037 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3040 if (this.brand !== '') {
3043 href: this.brand_href ? this.brand_href : '#',
3044 cls: 'navbar-brand',
3052 cfg.cls += ' main-nav';
3077 * @class Roo.bootstrap.NavSidebar
3078 * @extends Roo.bootstrap.Navbar
3079 * Bootstrap Sidebar class
3082 * Create a new Sidebar
3083 * @param {Object} config The config object
3087 Roo.bootstrap.NavSidebar = function(config){
3088 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3091 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3093 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3095 getAutoCreate : function(){
3100 cls: 'sidebar sidebar-nav'
3122 * @class Roo.bootstrap.NavGroup
3123 * @extends Roo.bootstrap.Component
3124 * Bootstrap NavGroup class
3125 * @cfg {String} align left | right
3126 * @cfg {Boolean} inverse false | true
3127 * @cfg {String} type (nav|pills|tab) default nav
3128 * @cfg {String} navId - reference Id for navbar.
3132 * Create a new nav group
3133 * @param {Object} config The config object
3136 Roo.bootstrap.NavGroup = function(config){
3137 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3139 Roo.bootstrap.NavGroup.register(this);
3143 * Fires when the active item changes
3144 * @param {Roo.bootstrap.NavGroup} this
3145 * @param {Roo.bootstrap.Navbar.Item} item The item selected
3146 * @param {Roo.bootstrap.Navbar.Item} item The previously selected item
3153 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3164 getAutoCreate : function()
3166 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3173 if (['tabs','pills'].indexOf(this.type)!==-1) {
3174 cfg.cls += ' nav-' + this.type
3176 if (this.type!=='nav') {
3177 Roo.log('nav type must be nav/tabs/pills')
3179 cfg.cls += ' navbar-nav'
3182 if (this.parent().sidebar) {
3185 cls: 'dashboard-menu sidebar-menu'
3191 if (this.form === true) {
3197 if (this.align === 'right') {
3198 cfg.cls += ' navbar-right';
3200 cfg.cls += ' navbar-left';
3204 if (this.align === 'right') {
3205 cfg.cls += ' navbar-right';
3209 cfg.cls += ' navbar-inverse';
3217 setActiveItem : function(item)
3220 Roo.each(this.navItems, function(v){
3225 v.setActive(false, true);
3232 item.setActive(true, true);
3233 this.fireEvent('changed', this, item, prev);
3238 addItem : function(cfg)
3240 var cn = new Roo.bootstrap.NavItem(cfg);
3242 cn.parentId = this.id;
3243 cn.onRender(this.el, null);
3247 register : function(item)
3249 this.navItems.push( item);
3250 item.navId = this.navId;
3253 getNavItem: function(tabId)
3256 Roo.each(this.navItems, function(e) {
3257 if (e.tabId == tabId) {
3273 Roo.apply(Roo.bootstrap.NavGroup, {
3277 register : function(navgrp)
3279 this.groups[navgrp.navId] = navgrp;
3282 get: function(navId) {
3283 return this.groups[navId];
3298 * @class Roo.bootstrap.NavItem
3299 * @extends Roo.bootstrap.Component
3300 * Bootstrap Navbar.NavItem class
3301 * @cfg {String} href link to
3302 * @cfg {String} html content of button
3303 * @cfg {String} badge text inside badge
3304 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3305 * @cfg {String} glyphicon name of glyphicon
3306 * @cfg {String} icon name of font awesome icon
3307 * @cfg {Boolean} active Is item active
3308 * @cfg {Boolean} disabled Is item disabled
3310 * @cfg {Boolean} preventDefault (true | false) default false
3311 * @cfg {String} tabId the tab that this item activates.
3312 * @cfg {String} tagtype (a|span) render as a href or span?
3315 * Create a new Navbar Item
3316 * @param {Object} config The config object
3318 Roo.bootstrap.NavItem = function(config){
3319 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3324 * The raw click event for the entire grid.
3325 * @param {Roo.EventObject} e
3330 * Fires when the active item active state changes
3331 * @param {Roo.bootstrap.NavItem} this
3332 * @param {boolean} state the new state
3340 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3348 preventDefault : false,
3353 getAutoCreate : function(){
3361 href : this.href || "#",
3362 html: this.html || ''
3368 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3371 // glyphicon and icon go before content..
3372 if (this.glyphicon || this.icon) {
3374 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3376 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3384 cfg.cn[0].html += " <span class='caret'></span>";
3388 if (this.badge !== '') {
3390 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3392 if (this.disabled) {
3393 cfg.cls += ' disabled';
3399 initEvents: function() {
3400 // Roo.log('init events?');
3401 // Roo.log(this.el.dom);
3402 if (typeof (this.menu) != 'undefined') {
3403 this.menu.parentType = this.xtype;
3404 this.menu.triggerEl = this.el;
3405 this.addxtype(Roo.apply({}, this.menu));
3409 this.el.select('a',true).on('click', this.onClick, this);
3410 // at this point parent should be available..
3411 this.parent().register(this);
3414 onClick : function(e)
3417 if(this.preventDefault){
3420 if (this.disabled) {
3423 Roo.log("fire event clicked");
3424 if(this.fireEvent('click', this, e) === false){
3428 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3429 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3430 this.parent().setActiveItem(this);
3438 isActive: function () {
3441 setActive : function(state, fire)
3443 this.active = state;
3445 this.el.removeClass('active');
3446 } else if (!this.el.hasClass('active')) {
3447 this.el.addClass('active');
3450 this.fireEvent('changed', this, state);
3455 // this should not be here...
3456 setDisabled : function(state)
3458 this.disabled = state;
3460 this.el.removeClass('disabled');
3461 } else if (!this.el.hasClass('disabled')) {
3462 this.el.addClass('disabled');
3475 * <span> icon </span>
3476 * <span> text </span>
3477 * <span>badge </span>
3481 * @class Roo.bootstrap.NavSidebarItem
3482 * @extends Roo.bootstrap.NavItem
3483 * Bootstrap Navbar.NavSidebarItem class
3485 * Create a new Navbar Button
3486 * @param {Object} config The config object
3488 Roo.bootstrap.NavSidebarItem = function(config){
3489 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3494 * The raw click event for the entire grid.
3495 * @param {Roo.EventObject} e
3500 * Fires when the active item active state changes
3501 * @param {Roo.bootstrap.NavSidebarItem} this
3502 * @param {boolean} state the new state
3510 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3513 getAutoCreate : function(){
3518 href : this.href || '#',
3530 html : this.html || ''
3535 cfg.cls += ' active';
3539 if (this.glyphicon || this.icon) {
3540 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3541 a.cn.push({ tag : 'i', cls : c }) ;
3546 if (this.badge !== '') {
3547 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3551 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3552 a.cls += 'dropdown-toggle treeview' ;
3576 * @class Roo.bootstrap.Row
3577 * @extends Roo.bootstrap.Component
3578 * Bootstrap Row class (contains columns...)
3582 * @param {Object} config The config object
3585 Roo.bootstrap.Row = function(config){
3586 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3589 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3591 getAutoCreate : function(){
3610 * @class Roo.bootstrap.Element
3611 * @extends Roo.bootstrap.Component
3612 * Bootstrap Element class
3613 * @cfg {String} html contents of the element
3614 * @cfg {String} tag tag of the element
3615 * @cfg {String} cls class of the element
3618 * Create a new Element
3619 * @param {Object} config The config object
3622 Roo.bootstrap.Element = function(config){
3623 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3626 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3633 getAutoCreate : function(){
3658 * @class Roo.bootstrap.Pagination
3659 * @extends Roo.bootstrap.Component
3660 * Bootstrap Pagination class
3661 * @cfg {String} size xs | sm | md | lg
3662 * @cfg {Boolean} inverse false | true
3665 * Create a new Pagination
3666 * @param {Object} config The config object
3669 Roo.bootstrap.Pagination = function(config){
3670 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3673 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3679 getAutoCreate : function(){
3685 cfg.cls += ' inverse';
3691 cfg.cls += " " + this.cls;
3709 * @class Roo.bootstrap.PaginationItem
3710 * @extends Roo.bootstrap.Component
3711 * Bootstrap PaginationItem class
3712 * @cfg {String} html text
3713 * @cfg {String} href the link
3714 * @cfg {Boolean} preventDefault (true | false) default true
3715 * @cfg {Boolean} active (true | false) default false
3719 * Create a new PaginationItem
3720 * @param {Object} config The config object
3724 Roo.bootstrap.PaginationItem = function(config){
3725 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3730 * The raw click event for the entire grid.
3731 * @param {Roo.EventObject} e
3737 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
3741 preventDefault: true,
3745 getAutoCreate : function(){
3751 href : this.href ? this.href : '#',
3752 html : this.html ? this.html : ''
3762 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
3768 initEvents: function() {
3770 this.el.on('click', this.onClick, this);
3773 onClick : function(e)
3775 Roo.log('PaginationItem on click ');
3776 if(this.preventDefault){
3780 this.fireEvent('click', this, e);
3796 * @class Roo.bootstrap.Slider
3797 * @extends Roo.bootstrap.Component
3798 * Bootstrap Slider class
3801 * Create a new Slider
3802 * @param {Object} config The config object
3805 Roo.bootstrap.Slider = function(config){
3806 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
3809 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
3811 getAutoCreate : function(){
3815 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
3819 cls: 'ui-slider-handle ui-state-default ui-corner-all'
3837 * @class Roo.bootstrap.Table
3838 * @extends Roo.bootstrap.Component
3839 * Bootstrap Table class
3840 * @cfg {String} cls table class
3841 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
3842 * @cfg {String} bgcolor Specifies the background color for a table
3843 * @cfg {Number} border Specifies whether the table cells should have borders or not
3844 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
3845 * @cfg {Number} cellspacing Specifies the space between cells
3846 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
3847 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
3848 * @cfg {String} sortable Specifies that the table should be sortable
3849 * @cfg {String} summary Specifies a summary of the content of a table
3850 * @cfg {Number} width Specifies the width of a table
3852 * @cfg {boolean} striped Should the rows be alternative striped
3853 * @cfg {boolean} bordered Add borders to the table
3854 * @cfg {boolean} hover Add hover highlighting
3855 * @cfg {boolean} condensed Format condensed
3856 * @cfg {boolean} responsive Format condensed
3857 * @cfg {Boolean} loadMask (true|false) default false
3859 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
3863 * Create a new Table
3864 * @param {Object} config The config object
3867 Roo.bootstrap.Table = function(config){
3868 Roo.bootstrap.Table.superclass.constructor.call(this, config);
3871 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
3872 this.sm = this.selModel;
3873 this.sm.xmodule = this.xmodule || false;
3875 if (this.cm && typeof(this.cm.config) == 'undefined') {
3876 this.colModel = new Roo.grid.ColumnModel(this.cm);
3877 this.cm = this.colModel;
3878 this.cm.xmodule = this.xmodule || false;
3881 this.store= Roo.factory(this.store, Roo.data);
3882 this.ds = this.store;
3883 this.ds.xmodule = this.xmodule || false;
3886 if (this.footer && this.store) {
3887 this.footer.dataSource = this.ds;
3888 this.footer = Roo.factory(this.footer);
3892 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
3915 getAutoCreate : function(){
3916 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
3925 cfg.cls += ' table-striped';
3928 cfg.cls += ' table-hover';
3930 if (this.bordered) {
3931 cfg.cls += ' table-bordered';
3933 if (this.condensed) {
3934 cfg.cls += ' table-condensed';
3936 if (this.responsive) {
3937 cfg.cls += ' table-responsive';
3944 cfg.cls+= ' ' +this.cls;
3947 // this lot should be simplifed...
3950 cfg.align=this.align;
3953 cfg.bgcolor=this.bgcolor;
3956 cfg.border=this.border;
3958 if (this.cellpadding) {
3959 cfg.cellpadding=this.cellpadding;
3961 if (this.cellspacing) {
3962 cfg.cellspacing=this.cellspacing;
3965 cfg.frame=this.frame;
3968 cfg.rules=this.rules;
3970 if (this.sortable) {
3971 cfg.sortable=this.sortable;
3974 cfg.summary=this.summary;
3977 cfg.width=this.width;
3980 if(this.store || this.cm){
3981 cfg.cn.push(this.renderHeader());
3982 cfg.cn.push(this.renderBody());
3983 cfg.cn.push(this.renderFooter());
3985 cfg.cls+= ' TableGrid';
3991 // initTableGrid : function()
4000 // var cm = this.cm;
4002 // for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4005 // html: cm.getColumnHeader(i)
4009 // cfg.push(header);
4016 initEvents : function()
4018 if(!this.store || !this.cm){
4022 Roo.log('initEvents with ds!!!!');
4026 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4027 e.on('click', _this.sort, _this);
4029 // this.maskEl = Roo.DomHelper.append(this.el.select('.TableGrid', true).first(), {tag: "div", cls:"x-dlg-mask"}, true);
4030 // this.maskEl.enableDisplayMode("block");
4031 // this.maskEl.show();
4033 this.parent().el.setStyle('position', 'relative');
4035 this.footer.parentId = this.id;
4036 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
4040 // mask should be using Roo.bootstrap.Mask...
4045 style: "text-align:center",
4049 style: "background-color:white;width:50%;margin:100 auto",
4053 src: rootURL + '/roojs1/images/ux/lightbox/loading.gif'
4064 this.maskEl = Roo.DomHelper.append(this.parent().el, mark, true);
4066 var size = this.parent().el.getSize();
4068 this.maskEl.setSize(size.width, 300); // we will fix the height at the beginning...
4070 this.maskEl.enableDisplayMode("block");
4072 this.store.on('load', this.onLoad, this);
4073 this.store.on('beforeload', this.onBeforeLoad, this);
4075 // load should be trigger on render..
4076 //this.store.load();
4082 sort : function(e,el)
4084 var col = Roo.get(el)
4086 if(!col.hasClass('sortable')){
4090 var sort = col.attr('sort');
4093 if(col.hasClass('glyphicon-arrow-up')){
4097 this.store.sortInfo = {field : sort, direction : dir};
4102 renderHeader : function()
4111 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4113 var config = cm.config[i];
4115 if(typeof(config.hidden) != 'undefined' && config.hidden){
4121 html: cm.getColumnHeader(i)
4124 if(typeof(config.dataIndex) != 'undefined'){
4125 c.sort = config.dataIndex;
4128 if(typeof(config.sortable) != 'undefined' && config.sortable){
4132 if(typeof(config.width) != 'undefined'){
4133 c.style = 'width:' + config.width + 'px';
4142 renderBody : function()
4152 renderFooter : function()
4174 Roo.log('ds onload');
4179 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4180 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
4182 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
4183 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
4186 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
4187 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
4191 var tbody = this.el.select('tbody', true).first();
4195 if(this.store.getCount() > 0){
4196 this.store.data.each(function(d){
4202 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4203 var config = cm.config[i];
4205 if(typeof(config.hidden) != 'undefined' && config.hidden){
4209 var renderer = cm.getRenderer(i);
4213 if(typeof(renderer) !== 'undefined'){
4214 value = renderer(d.data[cm.getDataIndex(i)], false, d);
4217 if(typeof(value) === 'object'){
4227 html: (typeof(value) === 'object') ? '' : value
4230 if(typeof(config.width) != 'undefined'){
4231 td.style = 'width:' + config.width + 'px';
4238 tbody.createChild(row);
4246 Roo.each(renders, function(r){
4247 _this.renderColumn(r);
4256 onBeforeLoad : function()
4258 Roo.log('ds onBeforeLoad');
4269 this.el.select('tbody', true).first().dom.innerHTML = '';
4272 getSelectionModel : function(){
4274 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
4276 return this.selModel;
4279 renderColumn : function(r)
4282 r.cfg.render(Roo.get(r.id));
4285 Roo.each(r.cfg.cn, function(c){
4290 _this.renderColumn(child);
4307 * @class Roo.bootstrap.TableCell
4308 * @extends Roo.bootstrap.Component
4309 * Bootstrap TableCell class
4310 * @cfg {String} html cell contain text
4311 * @cfg {String} cls cell class
4312 * @cfg {String} tag cell tag (td|th) default td
4313 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
4314 * @cfg {String} align Aligns the content in a cell
4315 * @cfg {String} axis Categorizes cells
4316 * @cfg {String} bgcolor Specifies the background color of a cell
4317 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
4318 * @cfg {Number} colspan Specifies the number of columns a cell should span
4319 * @cfg {String} headers Specifies one or more header cells a cell is related to
4320 * @cfg {Number} height Sets the height of a cell
4321 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
4322 * @cfg {Number} rowspan Sets the number of rows a cell should span
4323 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
4324 * @cfg {String} valign Vertical aligns the content in a cell
4325 * @cfg {Number} width Specifies the width of a cell
4328 * Create a new TableCell
4329 * @param {Object} config The config object
4332 Roo.bootstrap.TableCell = function(config){
4333 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
4336 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
4356 getAutoCreate : function(){
4357 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
4377 cfg.align=this.align
4383 cfg.bgcolor=this.bgcolor
4386 cfg.charoff=this.charoff
4389 cfg.colspan=this.colspan
4392 cfg.headers=this.headers
4395 cfg.height=this.height
4398 cfg.nowrap=this.nowrap
4401 cfg.rowspan=this.rowspan
4404 cfg.scope=this.scope
4407 cfg.valign=this.valign
4410 cfg.width=this.width
4429 * @class Roo.bootstrap.TableRow
4430 * @extends Roo.bootstrap.Component
4431 * Bootstrap TableRow class
4432 * @cfg {String} cls row class
4433 * @cfg {String} align Aligns the content in a table row
4434 * @cfg {String} bgcolor Specifies a background color for a table row
4435 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
4436 * @cfg {String} valign Vertical aligns the content in a table row
4439 * Create a new TableRow
4440 * @param {Object} config The config object
4443 Roo.bootstrap.TableRow = function(config){
4444 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
4447 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
4455 getAutoCreate : function(){
4456 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
4466 cfg.align = this.align;
4469 cfg.bgcolor = this.bgcolor;
4472 cfg.charoff = this.charoff;
4475 cfg.valign = this.valign;
4493 * @class Roo.bootstrap.TableBody
4494 * @extends Roo.bootstrap.Component
4495 * Bootstrap TableBody class
4496 * @cfg {String} cls element class
4497 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
4498 * @cfg {String} align Aligns the content inside the element
4499 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
4500 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
4503 * Create a new TableBody
4504 * @param {Object} config The config object
4507 Roo.bootstrap.TableBody = function(config){
4508 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
4511 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
4519 getAutoCreate : function(){
4520 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
4534 cfg.align = this.align;
4537 cfg.charoff = this.charoff;
4540 cfg.valign = this.valign;
4547 // initEvents : function()
4554 // this.store = Roo.factory(this.store, Roo.data);
4555 // this.store.on('load', this.onLoad, this);
4557 // this.store.load();
4561 // onLoad: function ()
4563 // this.fireEvent('load', this);
4573 * Ext JS Library 1.1.1
4574 * Copyright(c) 2006-2007, Ext JS, LLC.
4576 * Originally Released Under LGPL - original licence link has changed is not relivant.
4579 * <script type="text/javascript">
4582 // as we use this in bootstrap.
4583 Roo.namespace('Roo.form');
4585 * @class Roo.form.Action
4586 * Internal Class used to handle form actions
4588 * @param {Roo.form.BasicForm} el The form element or its id
4589 * @param {Object} config Configuration options
4594 // define the action interface
4595 Roo.form.Action = function(form, options){
4597 this.options = options || {};
4600 * Client Validation Failed
4603 Roo.form.Action.CLIENT_INVALID = 'client';
4605 * Server Validation Failed
4608 Roo.form.Action.SERVER_INVALID = 'server';
4610 * Connect to Server Failed
4613 Roo.form.Action.CONNECT_FAILURE = 'connect';
4615 * Reading Data from Server Failed
4618 Roo.form.Action.LOAD_FAILURE = 'load';
4620 Roo.form.Action.prototype = {
4622 failureType : undefined,
4623 response : undefined,
4627 run : function(options){
4632 success : function(response){
4637 handleResponse : function(response){
4641 // default connection failure
4642 failure : function(response){
4644 this.response = response;
4645 this.failureType = Roo.form.Action.CONNECT_FAILURE;
4646 this.form.afterAction(this, false);
4649 processResponse : function(response){
4650 this.response = response;
4651 if(!response.responseText){
4654 this.result = this.handleResponse(response);
4658 // utility functions used internally
4659 getUrl : function(appendParams){
4660 var url = this.options.url || this.form.url || this.form.el.dom.action;
4662 var p = this.getParams();
4664 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
4670 getMethod : function(){
4671 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
4674 getParams : function(){
4675 var bp = this.form.baseParams;
4676 var p = this.options.params;
4678 if(typeof p == "object"){
4679 p = Roo.urlEncode(Roo.applyIf(p, bp));
4680 }else if(typeof p == 'string' && bp){
4681 p += '&' + Roo.urlEncode(bp);
4684 p = Roo.urlEncode(bp);
4689 createCallback : function(){
4691 success: this.success,
4692 failure: this.failure,
4694 timeout: (this.form.timeout*1000),
4695 upload: this.form.fileUpload ? this.success : undefined
4700 Roo.form.Action.Submit = function(form, options){
4701 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
4704 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
4707 haveProgress : false,
4708 uploadComplete : false,
4710 // uploadProgress indicator.
4711 uploadProgress : function()
4713 if (!this.form.progressUrl) {
4717 if (!this.haveProgress) {
4718 Roo.MessageBox.progress("Uploading", "Uploading");
4720 if (this.uploadComplete) {
4721 Roo.MessageBox.hide();
4725 this.haveProgress = true;
4727 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
4729 var c = new Roo.data.Connection();
4731 url : this.form.progressUrl,
4736 success : function(req){
4737 //console.log(data);
4741 rdata = Roo.decode(req.responseText)
4743 Roo.log("Invalid data from server..");
4747 if (!rdata || !rdata.success) {
4749 Roo.MessageBox.alert(Roo.encode(rdata));
4752 var data = rdata.data;
4754 if (this.uploadComplete) {
4755 Roo.MessageBox.hide();
4760 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
4761 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
4764 this.uploadProgress.defer(2000,this);
4767 failure: function(data) {
4768 Roo.log('progress url failed ');
4779 // run get Values on the form, so it syncs any secondary forms.
4780 this.form.getValues();
4782 var o = this.options;
4783 var method = this.getMethod();
4784 var isPost = method == 'POST';
4785 if(o.clientValidation === false || this.form.isValid()){
4787 if (this.form.progressUrl) {
4788 this.form.findField('UPLOAD_IDENTIFIER').setValue(
4789 (new Date() * 1) + '' + Math.random());
4794 Roo.Ajax.request(Roo.apply(this.createCallback(), {
4795 form:this.form.el.dom,
4796 url:this.getUrl(!isPost),
4798 params:isPost ? this.getParams() : null,
4799 isUpload: this.form.fileUpload
4802 this.uploadProgress();
4804 }else if (o.clientValidation !== false){ // client validation failed
4805 this.failureType = Roo.form.Action.CLIENT_INVALID;
4806 this.form.afterAction(this, false);
4810 success : function(response)
4812 this.uploadComplete= true;
4813 if (this.haveProgress) {
4814 Roo.MessageBox.hide();
4818 var result = this.processResponse(response);
4819 if(result === true || result.success){
4820 this.form.afterAction(this, true);
4824 this.form.markInvalid(result.errors);
4825 this.failureType = Roo.form.Action.SERVER_INVALID;
4827 this.form.afterAction(this, false);
4829 failure : function(response)
4831 this.uploadComplete= true;
4832 if (this.haveProgress) {
4833 Roo.MessageBox.hide();
4836 this.response = response;
4837 this.failureType = Roo.form.Action.CONNECT_FAILURE;
4838 this.form.afterAction(this, false);
4841 handleResponse : function(response){
4842 if(this.form.errorReader){
4843 var rs = this.form.errorReader.read(response);
4846 for(var i = 0, len = rs.records.length; i < len; i++) {
4847 var r = rs.records[i];
4851 if(errors.length < 1){
4855 success : rs.success,
4861 ret = Roo.decode(response.responseText);
4865 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
4875 Roo.form.Action.Load = function(form, options){
4876 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
4877 this.reader = this.form.reader;
4880 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
4885 Roo.Ajax.request(Roo.apply(
4886 this.createCallback(), {
4887 method:this.getMethod(),
4888 url:this.getUrl(false),
4889 params:this.getParams()
4893 success : function(response){
4895 var result = this.processResponse(response);
4896 if(result === true || !result.success || !result.data){
4897 this.failureType = Roo.form.Action.LOAD_FAILURE;
4898 this.form.afterAction(this, false);
4901 this.form.clearInvalid();
4902 this.form.setValues(result.data);
4903 this.form.afterAction(this, true);
4906 handleResponse : function(response){
4907 if(this.form.reader){
4908 var rs = this.form.reader.read(response);
4909 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
4911 success : rs.success,
4915 return Roo.decode(response.responseText);
4919 Roo.form.Action.ACTION_TYPES = {
4920 'load' : Roo.form.Action.Load,
4921 'submit' : Roo.form.Action.Submit
4930 * @class Roo.bootstrap.Form
4931 * @extends Roo.bootstrap.Component
4932 * Bootstrap Form class
4933 * @cfg {String} method GET | POST (default POST)
4934 * @cfg {String} labelAlign top | left (default top)
4935 * @cfg {String} align left | right - for navbars
4940 * @param {Object} config The config object
4944 Roo.bootstrap.Form = function(config){
4945 Roo.bootstrap.Form.superclass.constructor.call(this, config);
4948 * @event clientvalidation
4949 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
4950 * @param {Form} this
4951 * @param {Boolean} valid true if the form has passed client-side validation
4953 clientvalidation: true,
4955 * @event beforeaction
4956 * Fires before any action is performed. Return false to cancel the action.
4957 * @param {Form} this
4958 * @param {Action} action The action to be performed
4962 * @event actionfailed
4963 * Fires when an action fails.
4964 * @param {Form} this
4965 * @param {Action} action The action that failed
4967 actionfailed : true,
4969 * @event actioncomplete
4970 * Fires when an action is completed.
4971 * @param {Form} this
4972 * @param {Action} action The action that completed
4974 actioncomplete : true
4979 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
4982 * @cfg {String} method
4983 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
4988 * The URL to use for form actions if one isn't supplied in the action options.
4991 * @cfg {Boolean} fileUpload
4992 * Set to true if this form is a file upload.
4996 * @cfg {Object} baseParams
4997 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
5001 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
5005 * @cfg {Sting} align (left|right) for navbar forms
5010 activeAction : null,
5013 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5014 * element by passing it or its id or mask the form itself by passing in true.
5017 waitMsgTarget : false,
5022 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5023 * element by passing it or its id or mask the form itself by passing in true.
5027 getAutoCreate : function(){
5031 method : this.method || 'POST',
5032 id : this.id || Roo.id(),
5035 if (this.parent().xtype.match(/^Nav/)) {
5036 cfg.cls = 'navbar-form navbar-' + this.align;
5040 if (this.labelAlign == 'left' ) {
5041 cfg.cls += ' form-horizontal';
5047 initEvents : function()
5049 this.el.on('submit', this.onSubmit, this);
5054 onSubmit : function(e){
5059 * Returns true if client-side validation on the form is successful.
5062 isValid : function(){
5063 var items = this.getItems();
5065 items.each(function(f){
5074 * Returns true if any fields in this form have changed since their original load.
5077 isDirty : function(){
5079 var items = this.getItems();
5080 items.each(function(f){
5090 * Performs a predefined action (submit or load) or custom actions you define on this form.
5091 * @param {String} actionName The name of the action type
5092 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
5093 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
5094 * accept other config options):
5096 Property Type Description
5097 ---------------- --------------- ----------------------------------------------------------------------------------
5098 url String The url for the action (defaults to the form's url)
5099 method String The form method to use (defaults to the form's method, or POST if not defined)
5100 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
5101 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
5102 validate the form on the client (defaults to false)
5104 * @return {BasicForm} this
5106 doAction : function(action, options){
5107 if(typeof action == 'string'){
5108 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
5110 if(this.fireEvent('beforeaction', this, action) !== false){
5111 this.beforeAction(action);
5112 action.run.defer(100, action);
5118 beforeAction : function(action){
5119 var o = action.options;
5121 // not really supported yet.. ??
5123 //if(this.waitMsgTarget === true){
5124 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
5125 //}else if(this.waitMsgTarget){
5126 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
5127 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
5129 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
5135 afterAction : function(action, success){
5136 this.activeAction = null;
5137 var o = action.options;
5139 //if(this.waitMsgTarget === true){
5141 //}else if(this.waitMsgTarget){
5142 // this.waitMsgTarget.unmask();
5144 // Roo.MessageBox.updateProgress(1);
5145 // Roo.MessageBox.hide();
5152 Roo.callback(o.success, o.scope, [this, action]);
5153 this.fireEvent('actioncomplete', this, action);
5157 // failure condition..
5158 // we have a scenario where updates need confirming.
5159 // eg. if a locking scenario exists..
5160 // we look for { errors : { needs_confirm : true }} in the response.
5162 (typeof(action.result) != 'undefined') &&
5163 (typeof(action.result.errors) != 'undefined') &&
5164 (typeof(action.result.errors.needs_confirm) != 'undefined')
5167 Roo.log("not supported yet");
5170 Roo.MessageBox.confirm(
5171 "Change requires confirmation",
5172 action.result.errorMsg,
5177 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
5187 Roo.callback(o.failure, o.scope, [this, action]);
5188 // show an error message if no failed handler is set..
5189 if (!this.hasListener('actionfailed')) {
5190 Roo.log("need to add dialog support");
5192 Roo.MessageBox.alert("Error",
5193 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
5194 action.result.errorMsg :
5195 "Saving Failed, please check your entries or try again"
5200 this.fireEvent('actionfailed', this, action);
5205 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
5206 * @param {String} id The value to search for
5209 findField : function(id){
5210 var items = this.getItems();
5211 var field = items.get(id);
5213 items.each(function(f){
5214 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
5221 return field || null;
5224 * Mark fields in this form invalid in bulk.
5225 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
5226 * @return {BasicForm} this
5228 markInvalid : function(errors){
5229 if(errors instanceof Array){
5230 for(var i = 0, len = errors.length; i < len; i++){
5231 var fieldError = errors[i];
5232 var f = this.findField(fieldError.id);
5234 f.markInvalid(fieldError.msg);
5240 if(typeof errors[id] != 'function' && (field = this.findField(id))){
5241 field.markInvalid(errors[id]);
5245 //Roo.each(this.childForms || [], function (f) {
5246 // f.markInvalid(errors);
5253 * Set values for fields in this form in bulk.
5254 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
5255 * @return {BasicForm} this
5257 setValues : function(values){
5258 if(values instanceof Array){ // array of objects
5259 for(var i = 0, len = values.length; i < len; i++){
5261 var f = this.findField(v.id);
5263 f.setValue(v.value);
5264 if(this.trackResetOnLoad){
5265 f.originalValue = f.getValue();
5269 }else{ // object hash
5272 if(typeof values[id] != 'function' && (field = this.findField(id))){
5274 if (field.setFromData &&
5276 field.displayField &&
5277 // combos' with local stores can
5278 // be queried via setValue()
5279 // to set their value..
5280 (field.store && !field.store.isLocal)
5284 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
5285 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
5286 field.setFromData(sd);
5289 field.setValue(values[id]);
5293 if(this.trackResetOnLoad){
5294 field.originalValue = field.getValue();
5300 //Roo.each(this.childForms || [], function (f) {
5301 // f.setValues(values);
5308 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
5309 * they are returned as an array.
5310 * @param {Boolean} asString
5313 getValues : function(asString){
5314 //if (this.childForms) {
5315 // copy values from the child forms
5316 // Roo.each(this.childForms, function (f) {
5317 // this.setValues(f.getValues());
5323 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
5324 if(asString === true){
5327 return Roo.urlDecode(fs);
5331 * Returns the fields in this form as an object with key/value pairs.
5332 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
5335 getFieldValues : function(with_hidden)
5337 var items = this.getItems();
5339 items.each(function(f){
5343 var v = f.getValue();
5344 if (f.inputType =='radio') {
5345 if (typeof(ret[f.getName()]) == 'undefined') {
5346 ret[f.getName()] = ''; // empty..
5349 if (!f.el.dom.checked) {
5357 // not sure if this supported any more..
5358 if ((typeof(v) == 'object') && f.getRawValue) {
5359 v = f.getRawValue() ; // dates..
5361 // combo boxes where name != hiddenName...
5362 if (f.name != f.getName()) {
5363 ret[f.name] = f.getRawValue();
5365 ret[f.getName()] = v;
5372 * Clears all invalid messages in this form.
5373 * @return {BasicForm} this
5375 clearInvalid : function(){
5376 var items = this.getItems();
5378 items.each(function(f){
5389 * @return {BasicForm} this
5392 var items = this.getItems();
5393 items.each(function(f){
5397 Roo.each(this.childForms || [], function (f) {
5404 getItems : function()
5406 var r=new Roo.util.MixedCollection(false, function(o){
5407 return o.id || (o.id = Roo.id());
5409 var iter = function(el) {
5416 Roo.each(el.items,function(e) {
5435 * Ext JS Library 1.1.1
5436 * Copyright(c) 2006-2007, Ext JS, LLC.
5438 * Originally Released Under LGPL - original licence link has changed is not relivant.
5441 * <script type="text/javascript">
5444 * @class Roo.form.VTypes
5445 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
5448 Roo.form.VTypes = function(){
5449 // closure these in so they are only created once.
5450 var alpha = /^[a-zA-Z_]+$/;
5451 var alphanum = /^[a-zA-Z0-9_]+$/;
5452 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
5453 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
5455 // All these messages and functions are configurable
5458 * The function used to validate email addresses
5459 * @param {String} value The email address
5461 'email' : function(v){
5462 return email.test(v);
5465 * The error text to display when the email validation function returns false
5468 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
5470 * The keystroke filter mask to be applied on email input
5473 'emailMask' : /[a-z0-9_\.\-@]/i,
5476 * The function used to validate URLs
5477 * @param {String} value The URL
5479 'url' : function(v){
5483 * The error text to display when the url validation function returns false
5486 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
5489 * The function used to validate alpha values
5490 * @param {String} value The value
5492 'alpha' : function(v){
5493 return alpha.test(v);
5496 * The error text to display when the alpha validation function returns false
5499 'alphaText' : 'This field should only contain letters and _',
5501 * The keystroke filter mask to be applied on alpha input
5504 'alphaMask' : /[a-z_]/i,
5507 * The function used to validate alphanumeric values
5508 * @param {String} value The value
5510 'alphanum' : function(v){
5511 return alphanum.test(v);
5514 * The error text to display when the alphanumeric validation function returns false
5517 'alphanumText' : 'This field should only contain letters, numbers and _',
5519 * The keystroke filter mask to be applied on alphanumeric input
5522 'alphanumMask' : /[a-z0-9_]/i
5532 * @class Roo.bootstrap.Input
5533 * @extends Roo.bootstrap.Component
5534 * Bootstrap Input class
5535 * @cfg {Boolean} disabled is it disabled
5536 * @cfg {String} fieldLabel - the label associated
5537 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
5538 * @cfg {String} name name of the input
5539 * @cfg {string} fieldLabel - the label associated
5540 * @cfg {string} inputType - input / file submit ...
5541 * @cfg {string} placeholder - placeholder to put in text.
5542 * @cfg {string} before - input group add on before
5543 * @cfg {string} after - input group add on after
5544 * @cfg {string} size - (lg|sm) or leave empty..
5545 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
5546 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
5547 * @cfg {Number} md colspan out of 12 for computer-sized screens
5548 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
5549 * @cfg {string} value default value of the input
5550 * @cfg {Number} labelWidth set the width of label (0-12)
5551 * @cfg {String} labelAlign (top|left)
5552 * @cfg {Boolean} readOnly Specifies that the field should be read-only
5556 * Create a new Input
5557 * @param {Object} config The config object
5560 Roo.bootstrap.Input = function(config){
5561 Roo.bootstrap.Input.superclass.constructor.call(this, config);
5566 * Fires when this field receives input focus.
5567 * @param {Roo.form.Field} this
5572 * Fires when this field loses input focus.
5573 * @param {Roo.form.Field} this
5578 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
5579 * {@link Roo.EventObject#getKey} to determine which key was pressed.
5580 * @param {Roo.form.Field} this
5581 * @param {Roo.EventObject} e The event object
5586 * Fires just before the field blurs if the field value has changed.
5587 * @param {Roo.form.Field} this
5588 * @param {Mixed} newValue The new value
5589 * @param {Mixed} oldValue The original value
5594 * Fires after the field has been marked as invalid.
5595 * @param {Roo.form.Field} this
5596 * @param {String} msg The validation message
5601 * Fires after the field has been validated with no errors.
5602 * @param {Roo.form.Field} this
5607 * Fires after the key up
5608 * @param {Roo.form.Field} this
5609 * @param {Roo.EventObject} e The event Object
5615 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
5617 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
5618 automatic validation (defaults to "keyup").
5620 validationEvent : "keyup",
5622 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
5624 validateOnBlur : true,
5626 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
5628 validationDelay : 250,
5630 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
5632 focusClass : "x-form-focus", // not needed???
5636 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
5638 invalidClass : "has-error",
5641 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
5643 selectOnFocus : false,
5646 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
5650 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
5655 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
5657 disableKeyFilter : false,
5660 * @cfg {Boolean} disabled True to disable the field (defaults to false).
5664 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
5668 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
5670 blankText : "This field is required",
5673 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
5677 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
5679 maxLength : Number.MAX_VALUE,
5681 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
5683 minLengthText : "The minimum length for this field is {0}",
5685 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
5687 maxLengthText : "The maximum length for this field is {0}",
5691 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
5692 * If available, this function will be called only after the basic validators all return true, and will be passed the
5693 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
5697 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
5698 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
5699 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
5703 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
5726 parentLabelAlign : function()
5729 while (parent.parent()) {
5730 parent = parent.parent();
5731 if (typeof(parent.labelAlign) !='undefined') {
5732 return parent.labelAlign;
5739 getAutoCreate : function(){
5741 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
5747 if(this.inputType != 'hidden'){
5748 cfg.cls = 'form-group' //input-group
5754 type : this.inputType,
5756 cls : 'form-control',
5757 placeholder : this.placeholder || ''
5761 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
5762 input.maxLength = this.maxLength;
5765 if (this.disabled) {
5766 input.disabled=true;
5769 if (this.readOnly) {
5770 input.readonly=true;
5774 input.name = this.name;
5777 input.cls += ' input-' + this.size;
5780 ['xs','sm','md','lg'].map(function(size){
5781 if (settings[size]) {
5782 cfg.cls += ' col-' + size + '-' + settings[size];
5786 var inputblock = input;
5788 if (this.before || this.after) {
5791 cls : 'input-group',
5794 if (this.before && typeof(this.before) == 'string') {
5796 inputblock.cn.push({
5798 cls : 'roo-input-before input-group-addon',
5802 if (this.before && typeof(this.before) == 'object') {
5803 this.before = Roo.factory(this.before);
5804 Roo.log(this.before);
5805 inputblock.cn.push({
5807 cls : 'roo-input-before input-group-' +
5808 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
5812 inputblock.cn.push(input);
5814 if (this.after && typeof(this.after) == 'string') {
5815 inputblock.cn.push({
5817 cls : 'roo-input-after input-group-addon',
5821 if (this.after && typeof(this.after) == 'object') {
5822 this.after = Roo.factory(this.after);
5823 Roo.log(this.after);
5824 inputblock.cn.push({
5826 cls : 'roo-input-after input-group-' +
5827 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
5832 if (align ==='left' && this.fieldLabel.length) {
5833 Roo.log("left and has label");
5839 cls : 'control-label col-sm-' + this.labelWidth,
5840 html : this.fieldLabel
5844 cls : "col-sm-" + (12 - this.labelWidth),
5851 } else if ( this.fieldLabel.length) {
5857 //cls : 'input-group-addon',
5858 html : this.fieldLabel
5868 Roo.log(" no label && no align");
5877 Roo.log('input-parentType: ' + this.parentType);
5879 if (this.parentType === 'Navbar' && this.parent().bar) {
5880 cfg.cls += ' navbar-form';
5888 * return the real input element.
5890 inputEl: function ()
5892 return this.el.select('input.form-control',true).first();
5894 setDisabled : function(v)
5896 var i = this.inputEl().dom;
5898 i.removeAttribute('disabled');
5902 i.setAttribute('disabled','true');
5904 initEvents : function()
5907 this.inputEl().on("keydown" , this.fireKey, this);
5908 this.inputEl().on("focus", this.onFocus, this);
5909 this.inputEl().on("blur", this.onBlur, this);
5911 this.inputEl().relayEvent('keyup', this);
5913 // reference to original value for reset
5914 this.originalValue = this.getValue();
5915 //Roo.form.TextField.superclass.initEvents.call(this);
5916 if(this.validationEvent == 'keyup'){
5917 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
5918 this.inputEl().on('keyup', this.filterValidation, this);
5920 else if(this.validationEvent !== false){
5921 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
5924 if(this.selectOnFocus){
5925 this.on("focus", this.preFocus, this);
5928 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
5929 this.inputEl().on("keypress", this.filterKeys, this);
5932 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
5933 this.el.on("click", this.autoSize, this);
5936 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
5937 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
5940 if (typeof(this.before) == 'object') {
5941 this.before.render(this.el.select('.roo-input-before',true).first());
5943 if (typeof(this.after) == 'object') {
5944 this.after.render(this.el.select('.roo-input-after',true).first());
5949 filterValidation : function(e){
5950 if(!e.isNavKeyPress()){
5951 this.validationTask.delay(this.validationDelay);
5955 * Validates the field value
5956 * @return {Boolean} True if the value is valid, else false
5958 validate : function(){
5959 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
5960 if(this.disabled || this.validateValue(this.getRawValue())){
5961 this.clearInvalid();
5969 * Validates a value according to the field's validation rules and marks the field as invalid
5970 * if the validation fails
5971 * @param {Mixed} value The value to validate
5972 * @return {Boolean} True if the value is valid, else false
5974 validateValue : function(value){
5975 if(value.length < 1) { // if it's blank
5976 if(this.allowBlank){
5977 this.clearInvalid();
5980 this.markInvalid(this.blankText);
5984 if(value.length < this.minLength){
5985 this.markInvalid(String.format(this.minLengthText, this.minLength));
5988 if(value.length > this.maxLength){
5989 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
5993 var vt = Roo.form.VTypes;
5994 if(!vt[this.vtype](value, this)){
5995 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
5999 if(typeof this.validator == "function"){
6000 var msg = this.validator(value);
6002 this.markInvalid(msg);
6006 if(this.regex && !this.regex.test(value)){
6007 this.markInvalid(this.regexText);
6016 fireKey : function(e){
6017 //Roo.log('field ' + e.getKey());
6018 if(e.isNavKeyPress()){
6019 this.fireEvent("specialkey", this, e);
6022 focus : function (selectText){
6024 this.inputEl().focus();
6025 if(selectText === true){
6026 this.inputEl().dom.select();
6032 onFocus : function(){
6033 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6034 // this.el.addClass(this.focusClass);
6037 this.hasFocus = true;
6038 this.startValue = this.getValue();
6039 this.fireEvent("focus", this);
6043 beforeBlur : Roo.emptyFn,
6047 onBlur : function(){
6049 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6050 //this.el.removeClass(this.focusClass);
6052 this.hasFocus = false;
6053 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
6056 var v = this.getValue();
6057 if(String(v) !== String(this.startValue)){
6058 this.fireEvent('change', this, v, this.startValue);
6060 this.fireEvent("blur", this);
6064 * Resets the current field value to the originally loaded value and clears any validation messages
6067 this.setValue(this.originalValue);
6068 this.clearInvalid();
6071 * Returns the name of the field
6072 * @return {Mixed} name The name field
6074 getName: function(){
6078 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
6079 * @return {Mixed} value The field value
6081 getValue : function(){
6082 return this.inputEl().getValue();
6085 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
6086 * @return {Mixed} value The field value
6088 getRawValue : function(){
6089 var v = this.inputEl().getValue();
6095 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
6096 * @param {Mixed} value The value to set
6098 setRawValue : function(v){
6099 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6102 selectText : function(start, end){
6103 var v = this.getRawValue();
6105 start = start === undefined ? 0 : start;
6106 end = end === undefined ? v.length : end;
6107 var d = this.inputEl().dom;
6108 if(d.setSelectionRange){
6109 d.setSelectionRange(start, end);
6110 }else if(d.createTextRange){
6111 var range = d.createTextRange();
6112 range.moveStart("character", start);
6113 range.moveEnd("character", v.length-end);
6120 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
6121 * @param {Mixed} value The value to set
6123 setValue : function(v){
6126 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6132 processValue : function(value){
6133 if(this.stripCharsRe){
6134 var newValue = value.replace(this.stripCharsRe, '');
6135 if(newValue !== value){
6136 this.setRawValue(newValue);
6143 preFocus : function(){
6145 if(this.selectOnFocus){
6146 this.inputEl().dom.select();
6149 filterKeys : function(e){
6151 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
6154 var c = e.getCharCode(), cc = String.fromCharCode(c);
6155 if(Roo.isIE && (e.isSpecialKey() || !cc)){
6158 if(!this.maskRe.test(cc)){
6163 * Clear any invalid styles/messages for this field
6165 clearInvalid : function(){
6167 if(!this.el || this.preventMark){ // not rendered
6170 this.el.removeClass(this.invalidClass);
6172 switch(this.msgTarget){
6174 this.el.dom.qtip = '';
6177 this.el.dom.title = '';
6181 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
6186 this.errorIcon.dom.qtip = '';
6187 this.errorIcon.hide();
6188 this.un('resize', this.alignErrorIcon, this);
6192 var t = Roo.getDom(this.msgTarget);
6194 t.style.display = 'none';
6198 this.fireEvent('valid', this);
6201 * Mark this field as invalid
6202 * @param {String} msg The validation message
6204 markInvalid : function(msg){
6205 if(!this.el || this.preventMark){ // not rendered
6208 this.el.addClass(this.invalidClass);
6210 msg = msg || this.invalidText;
6211 switch(this.msgTarget){
6213 this.el.dom.qtip = msg;
6214 this.el.dom.qclass = 'x-form-invalid-tip';
6215 if(Roo.QuickTips){ // fix for floating editors interacting with DND
6216 Roo.QuickTips.enable();
6220 this.el.dom.title = msg;
6224 var elp = this.el.findParent('.x-form-element', 5, true);
6225 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
6226 this.errorEl.setWidth(elp.getWidth(true)-20);
6228 this.errorEl.update(msg);
6229 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
6232 if(!this.errorIcon){
6233 var elp = this.el.findParent('.x-form-element', 5, true);
6234 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
6236 this.alignErrorIcon();
6237 this.errorIcon.dom.qtip = msg;
6238 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
6239 this.errorIcon.show();
6240 this.on('resize', this.alignErrorIcon, this);
6243 var t = Roo.getDom(this.msgTarget);
6245 t.style.display = this.msgDisplay;
6249 this.fireEvent('invalid', this, msg);
6252 SafariOnKeyDown : function(event)
6254 // this is a workaround for a password hang bug on chrome/ webkit.
6256 var isSelectAll = false;
6258 if(this.inputEl().dom.selectionEnd > 0){
6259 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
6261 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
6262 event.preventDefault();
6267 if(isSelectAll){ // backspace and delete key
6269 event.preventDefault();
6270 // this is very hacky as keydown always get's upper case.
6272 var cc = String.fromCharCode(event.getCharCode());
6273 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
6277 adjustWidth : function(tag, w){
6278 tag = tag.toLowerCase();
6279 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
6280 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
6284 if(tag == 'textarea'){
6287 }else if(Roo.isOpera){
6291 if(tag == 'textarea'){
6310 * @class Roo.bootstrap.TextArea
6311 * @extends Roo.bootstrap.Input
6312 * Bootstrap TextArea class
6313 * @cfg {Number} cols Specifies the visible width of a text area
6314 * @cfg {Number} rows Specifies the visible number of lines in a text area
6315 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
6316 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
6317 * @cfg {string} html text
6320 * Create a new TextArea
6321 * @param {Object} config The config object
6324 Roo.bootstrap.TextArea = function(config){
6325 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
6329 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
6339 getAutoCreate : function(){
6341 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6352 value : this.value || '',
6353 html: this.html || '',
6354 cls : 'form-control',
6355 placeholder : this.placeholder || ''
6359 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6360 input.maxLength = this.maxLength;
6364 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
6368 input.cols = this.cols;
6371 if (this.readOnly) {
6372 input.readonly = true;
6376 input.name = this.name;
6380 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
6384 ['xs','sm','md','lg'].map(function(size){
6385 if (settings[size]) {
6386 cfg.cls += ' col-' + size + '-' + settings[size];
6390 var inputblock = input;
6392 if (this.before || this.after) {
6395 cls : 'input-group',
6399 inputblock.cn.push({
6401 cls : 'input-group-addon',
6405 inputblock.cn.push(input);
6407 inputblock.cn.push({
6409 cls : 'input-group-addon',
6416 if (align ==='left' && this.fieldLabel.length) {
6417 Roo.log("left and has label");
6423 cls : 'control-label col-sm-' + this.labelWidth,
6424 html : this.fieldLabel
6428 cls : "col-sm-" + (12 - this.labelWidth),
6435 } else if ( this.fieldLabel.length) {
6441 //cls : 'input-group-addon',
6442 html : this.fieldLabel
6452 Roo.log(" no label && no align");
6462 if (this.disabled) {
6463 input.disabled=true;
6470 * return the real textarea element.
6472 inputEl: function ()
6474 return this.el.select('textarea.form-control',true).first();
6482 * trigger field - base class for combo..
6487 * @class Roo.bootstrap.TriggerField
6488 * @extends Roo.bootstrap.Input
6489 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
6490 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
6491 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
6492 * for which you can provide a custom implementation. For example:
6494 var trigger = new Roo.bootstrap.TriggerField();
6495 trigger.onTriggerClick = myTriggerFn;
6496 trigger.applyTo('my-field');
6499 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
6500 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
6501 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
6502 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
6504 * Create a new TriggerField.
6505 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
6506 * to the base TextField)
6508 Roo.bootstrap.TriggerField = function(config){
6509 this.mimicing = false;
6510 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
6513 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
6515 * @cfg {String} triggerClass A CSS class to apply to the trigger
6518 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
6522 /** @cfg {Boolean} grow @hide */
6523 /** @cfg {Number} growMin @hide */
6524 /** @cfg {Number} growMax @hide */
6530 autoSize: Roo.emptyFn,
6537 actionMode : 'wrap',
6541 getAutoCreate : function(){
6543 var parent = this.parent();
6545 var align = this.labelAlign || this.parentLabelAlign();
6550 cls: 'form-group' //input-group
6557 type : this.inputType,
6558 cls : 'form-control',
6559 autocomplete: 'off',
6560 placeholder : this.placeholder || ''
6564 input.name = this.name;
6567 input.cls += ' input-' + this.size;
6570 if (this.disabled) {
6571 input.disabled=true;
6574 var inputblock = input;
6576 if (this.before || this.after) {
6579 cls : 'input-group',
6583 inputblock.cn.push({
6585 cls : 'input-group-addon',
6589 inputblock.cn.push(input);
6591 inputblock.cn.push({
6593 cls : 'input-group-addon',
6606 cls: 'form-hidden-field'
6614 Roo.log('multiple');
6622 cls: 'form-hidden-field'
6626 cls: 'select2-choices',
6630 cls: 'select2-search-field',
6643 cls: 'select2-container input-group',
6648 cls: 'typeahead typeahead-long dropdown-menu',
6649 style: 'display:none'
6657 cls : 'input-group-addon btn dropdown-toggle',
6665 cls: 'combobox-clear',
6679 combobox.cls += ' select2-container-multi';
6682 if (align ==='left' && this.fieldLabel.length) {
6684 Roo.log("left and has label");
6690 cls : 'control-label col-sm-' + this.labelWidth,
6691 html : this.fieldLabel
6695 cls : "col-sm-" + (12 - this.labelWidth),
6702 } else if ( this.fieldLabel.length) {
6708 //cls : 'input-group-addon',
6709 html : this.fieldLabel
6719 Roo.log(" no label && no align");
6726 ['xs','sm','md','lg'].map(function(size){
6727 if (settings[size]) {
6728 cfg.cls += ' col-' + size + '-' + settings[size];
6739 onResize : function(w, h){
6740 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
6741 // if(typeof w == 'number'){
6742 // var x = w - this.trigger.getWidth();
6743 // this.inputEl().setWidth(this.adjustWidth('input', x));
6744 // this.trigger.setStyle('left', x+'px');
6749 adjustSize : Roo.BoxComponent.prototype.adjustSize,
6752 getResizeEl : function(){
6753 return this.inputEl();
6757 getPositionEl : function(){
6758 return this.inputEl();
6762 alignErrorIcon : function(){
6763 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
6767 initEvents : function(){
6769 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
6770 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
6772 this.trigger = this.el.select('span.dropdown-toggle',true).first();
6773 if(this.hideTrigger){
6774 this.trigger.setDisplayed(false);
6776 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
6780 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
6783 //this.trigger.addClassOnOver('x-form-trigger-over');
6784 //this.trigger.addClassOnClick('x-form-trigger-click');
6787 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
6792 initTrigger : function(){
6797 onDestroy : function(){
6799 this.trigger.removeAllListeners();
6800 // this.trigger.remove();
6803 // this.wrap.remove();
6805 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
6809 onFocus : function(){
6810 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
6813 this.wrap.addClass('x-trigger-wrap-focus');
6814 this.mimicing = true;
6815 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
6816 if(this.monitorTab){
6817 this.el.on("keydown", this.checkTab, this);
6824 checkTab : function(e){
6825 if(e.getKey() == e.TAB){
6831 onBlur : function(){
6836 mimicBlur : function(e, t){
6838 if(!this.wrap.contains(t) && this.validateBlur()){
6845 triggerBlur : function(){
6846 this.mimicing = false;
6847 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
6848 if(this.monitorTab){
6849 this.el.un("keydown", this.checkTab, this);
6851 //this.wrap.removeClass('x-trigger-wrap-focus');
6852 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
6856 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
6857 validateBlur : function(e, t){
6862 onDisable : function(){
6863 this.inputEl().dom.disabled = true;
6864 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
6866 // this.wrap.addClass('x-item-disabled');
6871 onEnable : function(){
6872 this.inputEl().dom.disabled = false;
6873 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
6875 // this.el.removeClass('x-item-disabled');
6880 onShow : function(){
6881 var ae = this.getActionEl();
6884 ae.dom.style.display = '';
6885 ae.dom.style.visibility = 'visible';
6891 onHide : function(){
6892 var ae = this.getActionEl();
6893 ae.dom.style.display = 'none';
6897 * The function that should handle the trigger's click event. This method does nothing by default until overridden
6898 * by an implementing function.
6900 * @param {EventObject} e
6902 onTriggerClick : Roo.emptyFn
6906 * Ext JS Library 1.1.1
6907 * Copyright(c) 2006-2007, Ext JS, LLC.
6909 * Originally Released Under LGPL - original licence link has changed is not relivant.
6912 * <script type="text/javascript">
6917 * @class Roo.data.SortTypes
6919 * Defines the default sorting (casting?) comparison functions used when sorting data.
6921 Roo.data.SortTypes = {
6923 * Default sort that does nothing
6924 * @param {Mixed} s The value being converted
6925 * @return {Mixed} The comparison value
6932 * The regular expression used to strip tags
6936 stripTagsRE : /<\/?[^>]+>/gi,
6939 * Strips all HTML tags to sort on text only
6940 * @param {Mixed} s The value being converted
6941 * @return {String} The comparison value
6943 asText : function(s){
6944 return String(s).replace(this.stripTagsRE, "");
6948 * Strips all HTML tags to sort on text only - Case insensitive
6949 * @param {Mixed} s The value being converted
6950 * @return {String} The comparison value
6952 asUCText : function(s){
6953 return String(s).toUpperCase().replace(this.stripTagsRE, "");
6957 * Case insensitive string
6958 * @param {Mixed} s The value being converted
6959 * @return {String} The comparison value
6961 asUCString : function(s) {
6962 return String(s).toUpperCase();
6967 * @param {Mixed} s The value being converted
6968 * @return {Number} The comparison value
6970 asDate : function(s) {
6974 if(s instanceof Date){
6977 return Date.parse(String(s));
6982 * @param {Mixed} s The value being converted
6983 * @return {Float} The comparison value
6985 asFloat : function(s) {
6986 var val = parseFloat(String(s).replace(/,/g, ""));
6987 if(isNaN(val)) val = 0;
6993 * @param {Mixed} s The value being converted
6994 * @return {Number} The comparison value
6996 asInt : function(s) {
6997 var val = parseInt(String(s).replace(/,/g, ""));
6998 if(isNaN(val)) val = 0;
7003 * Ext JS Library 1.1.1
7004 * Copyright(c) 2006-2007, Ext JS, LLC.
7006 * Originally Released Under LGPL - original licence link has changed is not relivant.
7009 * <script type="text/javascript">
7013 * @class Roo.data.Record
7014 * Instances of this class encapsulate both record <em>definition</em> information, and record
7015 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
7016 * to access Records cached in an {@link Roo.data.Store} object.<br>
7018 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
7019 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
7022 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
7024 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
7025 * {@link #create}. The parameters are the same.
7026 * @param {Array} data An associative Array of data values keyed by the field name.
7027 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
7028 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
7029 * not specified an integer id is generated.
7031 Roo.data.Record = function(data, id){
7032 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
7037 * Generate a constructor for a specific record layout.
7038 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
7039 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
7040 * Each field definition object may contain the following properties: <ul>
7041 * <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,
7042 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
7043 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
7044 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
7045 * is being used, then this is a string containing the javascript expression to reference the data relative to
7046 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
7047 * to the data item relative to the record element. If the mapping expression is the same as the field name,
7048 * this may be omitted.</p></li>
7049 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
7050 * <ul><li>auto (Default, implies no conversion)</li>
7055 * <li>date</li></ul></p></li>
7056 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
7057 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
7058 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
7059 * by the Reader into an object that will be stored in the Record. It is passed the
7060 * following parameters:<ul>
7061 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
7063 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
7065 * <br>usage:<br><pre><code>
7066 var TopicRecord = Roo.data.Record.create(
7067 {name: 'title', mapping: 'topic_title'},
7068 {name: 'author', mapping: 'username'},
7069 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
7070 {name: 'lastPost', mapping: 'post_time', type: 'date'},
7071 {name: 'lastPoster', mapping: 'user2'},
7072 {name: 'excerpt', mapping: 'post_text'}
7075 var myNewRecord = new TopicRecord({
7076 title: 'Do my job please',
7079 lastPost: new Date(),
7080 lastPoster: 'Animal',
7081 excerpt: 'No way dude!'
7083 myStore.add(myNewRecord);
7088 Roo.data.Record.create = function(o){
7090 f.superclass.constructor.apply(this, arguments);
7092 Roo.extend(f, Roo.data.Record);
7093 var p = f.prototype;
7094 p.fields = new Roo.util.MixedCollection(false, function(field){
7097 for(var i = 0, len = o.length; i < len; i++){
7098 p.fields.add(new Roo.data.Field(o[i]));
7100 f.getField = function(name){
7101 return p.fields.get(name);
7106 Roo.data.Record.AUTO_ID = 1000;
7107 Roo.data.Record.EDIT = 'edit';
7108 Roo.data.Record.REJECT = 'reject';
7109 Roo.data.Record.COMMIT = 'commit';
7111 Roo.data.Record.prototype = {
7113 * Readonly flag - true if this record has been modified.
7122 join : function(store){
7127 * Set the named field to the specified value.
7128 * @param {String} name The name of the field to set.
7129 * @param {Object} value The value to set the field to.
7131 set : function(name, value){
7132 if(this.data[name] == value){
7139 if(typeof this.modified[name] == 'undefined'){
7140 this.modified[name] = this.data[name];
7142 this.data[name] = value;
7143 if(!this.editing && this.store){
7144 this.store.afterEdit(this);
7149 * Get the value of the named field.
7150 * @param {String} name The name of the field to get the value of.
7151 * @return {Object} The value of the field.
7153 get : function(name){
7154 return this.data[name];
7158 beginEdit : function(){
7159 this.editing = true;
7164 cancelEdit : function(){
7165 this.editing = false;
7166 delete this.modified;
7170 endEdit : function(){
7171 this.editing = false;
7172 if(this.dirty && this.store){
7173 this.store.afterEdit(this);
7178 * Usually called by the {@link Roo.data.Store} which owns the Record.
7179 * Rejects all changes made to the Record since either creation, or the last commit operation.
7180 * Modified fields are reverted to their original values.
7182 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
7183 * of reject operations.
7185 reject : function(){
7186 var m = this.modified;
7188 if(typeof m[n] != "function"){
7189 this.data[n] = m[n];
7193 delete this.modified;
7194 this.editing = false;
7196 this.store.afterReject(this);
7201 * Usually called by the {@link Roo.data.Store} which owns the Record.
7202 * Commits all changes made to the Record since either creation, or the last commit operation.
7204 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
7205 * of commit operations.
7207 commit : function(){
7209 delete this.modified;
7210 this.editing = false;
7212 this.store.afterCommit(this);
7217 hasError : function(){
7218 return this.error != null;
7222 clearError : function(){
7227 * Creates a copy of this record.
7228 * @param {String} id (optional) A new record id if you don't want to use this record's id
7231 copy : function(newId) {
7232 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
7236 * Ext JS Library 1.1.1
7237 * Copyright(c) 2006-2007, Ext JS, LLC.
7239 * Originally Released Under LGPL - original licence link has changed is not relivant.
7242 * <script type="text/javascript">
7248 * @class Roo.data.Store
7249 * @extends Roo.util.Observable
7250 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
7251 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
7253 * 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
7254 * has no knowledge of the format of the data returned by the Proxy.<br>
7256 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
7257 * instances from the data object. These records are cached and made available through accessor functions.
7259 * Creates a new Store.
7260 * @param {Object} config A config object containing the objects needed for the Store to access data,
7261 * and read the data into Records.
7263 Roo.data.Store = function(config){
7264 this.data = new Roo.util.MixedCollection(false);
7265 this.data.getKey = function(o){
7268 this.baseParams = {};
7275 "multisort" : "_multisort"
7278 if(config && config.data){
7279 this.inlineData = config.data;
7283 Roo.apply(this, config);
7285 if(this.reader){ // reader passed
7286 this.reader = Roo.factory(this.reader, Roo.data);
7287 this.reader.xmodule = this.xmodule || false;
7288 if(!this.recordType){
7289 this.recordType = this.reader.recordType;
7291 if(this.reader.onMetaChange){
7292 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
7296 if(this.recordType){
7297 this.fields = this.recordType.prototype.fields;
7303 * @event datachanged
7304 * Fires when the data cache has changed, and a widget which is using this Store
7305 * as a Record cache should refresh its view.
7306 * @param {Store} this
7311 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
7312 * @param {Store} this
7313 * @param {Object} meta The JSON metadata
7318 * Fires when Records have been added to the Store
7319 * @param {Store} this
7320 * @param {Roo.data.Record[]} records The array of Records added
7321 * @param {Number} index The index at which the record(s) were added
7326 * Fires when a Record has been removed from the Store
7327 * @param {Store} this
7328 * @param {Roo.data.Record} record The Record that was removed
7329 * @param {Number} index The index at which the record was removed
7334 * Fires when a Record has been updated
7335 * @param {Store} this
7336 * @param {Roo.data.Record} record The Record that was updated
7337 * @param {String} operation The update operation being performed. Value may be one of:
7339 Roo.data.Record.EDIT
7340 Roo.data.Record.REJECT
7341 Roo.data.Record.COMMIT
7347 * Fires when the data cache has been cleared.
7348 * @param {Store} this
7353 * Fires before a request is made for a new data object. If the beforeload handler returns false
7354 * the load action will be canceled.
7355 * @param {Store} this
7356 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7360 * @event beforeloadadd
7361 * Fires after a new set of Records has been loaded.
7362 * @param {Store} this
7363 * @param {Roo.data.Record[]} records The Records that were loaded
7364 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7366 beforeloadadd : true,
7369 * Fires after a new set of Records has been loaded, before they are added to the store.
7370 * @param {Store} this
7371 * @param {Roo.data.Record[]} records The Records that were loaded
7372 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7373 * @params {Object} return from reader
7377 * @event loadexception
7378 * Fires if an exception occurs in the Proxy during loading.
7379 * Called with the signature of the Proxy's "loadexception" event.
7380 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
7383 * @param {Object} return from JsonData.reader() - success, totalRecords, records
7384 * @param {Object} load options
7385 * @param {Object} jsonData from your request (normally this contains the Exception)
7387 loadexception : true
7391 this.proxy = Roo.factory(this.proxy, Roo.data);
7392 this.proxy.xmodule = this.xmodule || false;
7393 this.relayEvents(this.proxy, ["loadexception"]);
7395 this.sortToggle = {};
7396 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
7398 Roo.data.Store.superclass.constructor.call(this);
7400 if(this.inlineData){
7401 this.loadData(this.inlineData);
7402 delete this.inlineData;
7406 Roo.extend(Roo.data.Store, Roo.util.Observable, {
7408 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
7409 * without a remote query - used by combo/forms at present.
7413 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
7416 * @cfg {Array} data Inline data to be loaded when the store is initialized.
7419 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
7420 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
7423 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
7424 * on any HTTP request
7427 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
7430 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
7434 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
7435 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
7440 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
7441 * loaded or when a record is removed. (defaults to false).
7443 pruneModifiedRecords : false,
7449 * Add Records to the Store and fires the add event.
7450 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
7452 add : function(records){
7453 records = [].concat(records);
7454 for(var i = 0, len = records.length; i < len; i++){
7455 records[i].join(this);
7457 var index = this.data.length;
7458 this.data.addAll(records);
7459 this.fireEvent("add", this, records, index);
7463 * Remove a Record from the Store and fires the remove event.
7464 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
7466 remove : function(record){
7467 var index = this.data.indexOf(record);
7468 this.data.removeAt(index);
7469 if(this.pruneModifiedRecords){
7470 this.modified.remove(record);
7472 this.fireEvent("remove", this, record, index);
7476 * Remove all Records from the Store and fires the clear event.
7478 removeAll : function(){
7480 if(this.pruneModifiedRecords){
7483 this.fireEvent("clear", this);
7487 * Inserts Records to the Store at the given index and fires the add event.
7488 * @param {Number} index The start index at which to insert the passed Records.
7489 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
7491 insert : function(index, records){
7492 records = [].concat(records);
7493 for(var i = 0, len = records.length; i < len; i++){
7494 this.data.insert(index, records[i]);
7495 records[i].join(this);
7497 this.fireEvent("add", this, records, index);
7501 * Get the index within the cache of the passed Record.
7502 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
7503 * @return {Number} The index of the passed Record. Returns -1 if not found.
7505 indexOf : function(record){
7506 return this.data.indexOf(record);
7510 * Get the index within the cache of the Record with the passed id.
7511 * @param {String} id The id of the Record to find.
7512 * @return {Number} The index of the Record. Returns -1 if not found.
7514 indexOfId : function(id){
7515 return this.data.indexOfKey(id);
7519 * Get the Record with the specified id.
7520 * @param {String} id The id of the Record to find.
7521 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
7523 getById : function(id){
7524 return this.data.key(id);
7528 * Get the Record at the specified index.
7529 * @param {Number} index The index of the Record to find.
7530 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
7532 getAt : function(index){
7533 return this.data.itemAt(index);
7537 * Returns a range of Records between specified indices.
7538 * @param {Number} startIndex (optional) The starting index (defaults to 0)
7539 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
7540 * @return {Roo.data.Record[]} An array of Records
7542 getRange : function(start, end){
7543 return this.data.getRange(start, end);
7547 storeOptions : function(o){
7548 o = Roo.apply({}, o);
7551 this.lastOptions = o;
7555 * Loads the Record cache from the configured Proxy using the configured Reader.
7557 * If using remote paging, then the first load call must specify the <em>start</em>
7558 * and <em>limit</em> properties in the options.params property to establish the initial
7559 * position within the dataset, and the number of Records to cache on each read from the Proxy.
7561 * <strong>It is important to note that for remote data sources, loading is asynchronous,
7562 * and this call will return before the new data has been loaded. Perform any post-processing
7563 * in a callback function, or in a "load" event handler.</strong>
7565 * @param {Object} options An object containing properties which control loading options:<ul>
7566 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
7567 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
7568 * passed the following arguments:<ul>
7569 * <li>r : Roo.data.Record[]</li>
7570 * <li>options: Options object from the load call</li>
7571 * <li>success: Boolean success indicator</li></ul></li>
7572 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
7573 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
7576 load : function(options){
7577 options = options || {};
7578 if(this.fireEvent("beforeload", this, options) !== false){
7579 this.storeOptions(options);
7580 var p = Roo.apply(options.params || {}, this.baseParams);
7581 // if meta was not loaded from remote source.. try requesting it.
7582 if (!this.reader.metaFromRemote) {
7585 if(this.sortInfo && this.remoteSort){
7586 var pn = this.paramNames;
7587 p[pn["sort"]] = this.sortInfo.field;
7588 p[pn["dir"]] = this.sortInfo.direction;
7590 if (this.multiSort) {
7591 var pn = this.paramNames;
7592 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
7595 this.proxy.load(p, this.reader, this.loadRecords, this, options);
7600 * Reloads the Record cache from the configured Proxy using the configured Reader and
7601 * the options from the last load operation performed.
7602 * @param {Object} options (optional) An object containing properties which may override the options
7603 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
7604 * the most recently used options are reused).
7606 reload : function(options){
7607 this.load(Roo.applyIf(options||{}, this.lastOptions));
7611 // Called as a callback by the Reader during a load operation.
7612 loadRecords : function(o, options, success){
7613 if(!o || success === false){
7614 if(success !== false){
7615 this.fireEvent("load", this, [], options, o);
7617 if(options.callback){
7618 options.callback.call(options.scope || this, [], options, false);
7622 // if data returned failure - throw an exception.
7623 if (o.success === false) {
7624 // show a message if no listener is registered.
7625 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
7626 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
7628 // loadmask wil be hooked into this..
7629 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
7632 var r = o.records, t = o.totalRecords || r.length;
7634 this.fireEvent("beforeloadadd", this, r, options, o);
7636 if(!options || options.add !== true){
7637 if(this.pruneModifiedRecords){
7640 for(var i = 0, len = r.length; i < len; i++){
7644 this.data = this.snapshot;
7645 delete this.snapshot;
7648 this.data.addAll(r);
7649 this.totalLength = t;
7651 this.fireEvent("datachanged", this);
7653 this.totalLength = Math.max(t, this.data.length+r.length);
7656 this.fireEvent("load", this, r, options, o);
7657 if(options.callback){
7658 options.callback.call(options.scope || this, r, options, true);
7664 * Loads data from a passed data block. A Reader which understands the format of the data
7665 * must have been configured in the constructor.
7666 * @param {Object} data The data block from which to read the Records. The format of the data expected
7667 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
7668 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
7670 loadData : function(o, append){
7671 var r = this.reader.readRecords(o);
7672 this.loadRecords(r, {add: append}, true);
7676 * Gets the number of cached records.
7678 * <em>If using paging, this may not be the total size of the dataset. If the data object
7679 * used by the Reader contains the dataset size, then the getTotalCount() function returns
7680 * the data set size</em>
7682 getCount : function(){
7683 return this.data.length || 0;
7687 * Gets the total number of records in the dataset as returned by the server.
7689 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
7690 * the dataset size</em>
7692 getTotalCount : function(){
7693 return this.totalLength || 0;
7697 * Returns the sort state of the Store as an object with two properties:
7699 field {String} The name of the field by which the Records are sorted
7700 direction {String} The sort order, "ASC" or "DESC"
7703 getSortState : function(){
7704 return this.sortInfo;
7708 applySort : function(){
7709 if(this.sortInfo && !this.remoteSort){
7710 var s = this.sortInfo, f = s.field;
7711 var st = this.fields.get(f).sortType;
7712 var fn = function(r1, r2){
7713 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
7714 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
7716 this.data.sort(s.direction, fn);
7717 if(this.snapshot && this.snapshot != this.data){
7718 this.snapshot.sort(s.direction, fn);
7724 * Sets the default sort column and order to be used by the next load operation.
7725 * @param {String} fieldName The name of the field to sort by.
7726 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
7728 setDefaultSort : function(field, dir){
7729 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
7734 * If remote sorting is used, the sort is performed on the server, and the cache is
7735 * reloaded. If local sorting is used, the cache is sorted internally.
7736 * @param {String} fieldName The name of the field to sort by.
7737 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
7739 sort : function(fieldName, dir){
7740 var f = this.fields.get(fieldName);
7742 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
7744 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
7745 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
7750 this.sortToggle[f.name] = dir;
7751 this.sortInfo = {field: f.name, direction: dir};
7752 if(!this.remoteSort){
7754 this.fireEvent("datachanged", this);
7756 this.load(this.lastOptions);
7761 * Calls the specified function for each of the Records in the cache.
7762 * @param {Function} fn The function to call. The Record is passed as the first parameter.
7763 * Returning <em>false</em> aborts and exits the iteration.
7764 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
7766 each : function(fn, scope){
7767 this.data.each(fn, scope);
7771 * Gets all records modified since the last commit. Modified records are persisted across load operations
7772 * (e.g., during paging).
7773 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
7775 getModifiedRecords : function(){
7776 return this.modified;
7780 createFilterFn : function(property, value, anyMatch){
7781 if(!value.exec){ // not a regex
7782 value = String(value);
7783 if(value.length == 0){
7786 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
7789 return value.test(r.data[property]);
7794 * Sums the value of <i>property</i> for each record between start and end and returns the result.
7795 * @param {String} property A field on your records
7796 * @param {Number} start The record index to start at (defaults to 0)
7797 * @param {Number} end The last record index to include (defaults to length - 1)
7798 * @return {Number} The sum
7800 sum : function(property, start, end){
7801 var rs = this.data.items, v = 0;
7803 end = (end || end === 0) ? end : rs.length-1;
7805 for(var i = start; i <= end; i++){
7806 v += (rs[i].data[property] || 0);
7812 * Filter the records by a specified property.
7813 * @param {String} field A field on your records
7814 * @param {String/RegExp} value Either a string that the field
7815 * should start with or a RegExp to test against the field
7816 * @param {Boolean} anyMatch True to match any part not just the beginning
7818 filter : function(property, value, anyMatch){
7819 var fn = this.createFilterFn(property, value, anyMatch);
7820 return fn ? this.filterBy(fn) : this.clearFilter();
7824 * Filter by a function. The specified function will be called with each
7825 * record in this data source. If the function returns true the record is included,
7826 * otherwise it is filtered.
7827 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
7828 * @param {Object} scope (optional) The scope of the function (defaults to this)
7830 filterBy : function(fn, scope){
7831 this.snapshot = this.snapshot || this.data;
7832 this.data = this.queryBy(fn, scope||this);
7833 this.fireEvent("datachanged", this);
7837 * Query the records by a specified property.
7838 * @param {String} field A field on your records
7839 * @param {String/RegExp} value Either a string that the field
7840 * should start with or a RegExp to test against the field
7841 * @param {Boolean} anyMatch True to match any part not just the beginning
7842 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
7844 query : function(property, value, anyMatch){
7845 var fn = this.createFilterFn(property, value, anyMatch);
7846 return fn ? this.queryBy(fn) : this.data.clone();
7850 * Query by a function. The specified function will be called with each
7851 * record in this data source. If the function returns true the record is included
7853 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
7854 * @param {Object} scope (optional) The scope of the function (defaults to this)
7855 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
7857 queryBy : function(fn, scope){
7858 var data = this.snapshot || this.data;
7859 return data.filterBy(fn, scope||this);
7863 * Collects unique values for a particular dataIndex from this store.
7864 * @param {String} dataIndex The property to collect
7865 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
7866 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
7867 * @return {Array} An array of the unique values
7869 collect : function(dataIndex, allowNull, bypassFilter){
7870 var d = (bypassFilter === true && this.snapshot) ?
7871 this.snapshot.items : this.data.items;
7872 var v, sv, r = [], l = {};
7873 for(var i = 0, len = d.length; i < len; i++){
7874 v = d[i].data[dataIndex];
7876 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
7885 * Revert to a view of the Record cache with no filtering applied.
7886 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
7888 clearFilter : function(suppressEvent){
7889 if(this.snapshot && this.snapshot != this.data){
7890 this.data = this.snapshot;
7891 delete this.snapshot;
7892 if(suppressEvent !== true){
7893 this.fireEvent("datachanged", this);
7899 afterEdit : function(record){
7900 if(this.modified.indexOf(record) == -1){
7901 this.modified.push(record);
7903 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
7907 afterReject : function(record){
7908 this.modified.remove(record);
7909 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
7913 afterCommit : function(record){
7914 this.modified.remove(record);
7915 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
7919 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
7920 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
7922 commitChanges : function(){
7923 var m = this.modified.slice(0);
7925 for(var i = 0, len = m.length; i < len; i++){
7931 * Cancel outstanding changes on all changed records.
7933 rejectChanges : function(){
7934 var m = this.modified.slice(0);
7936 for(var i = 0, len = m.length; i < len; i++){
7941 onMetaChange : function(meta, rtype, o){
7942 this.recordType = rtype;
7943 this.fields = rtype.prototype.fields;
7944 delete this.snapshot;
7945 this.sortInfo = meta.sortInfo || this.sortInfo;
7947 this.fireEvent('metachange', this, this.reader.meta);
7950 moveIndex : function(data, type)
7952 var index = this.indexOf(data);
7954 var newIndex = index + type;
7958 this.insert(newIndex, data);
7963 * Ext JS Library 1.1.1
7964 * Copyright(c) 2006-2007, Ext JS, LLC.
7966 * Originally Released Under LGPL - original licence link has changed is not relivant.
7969 * <script type="text/javascript">
7973 * @class Roo.data.SimpleStore
7974 * @extends Roo.data.Store
7975 * Small helper class to make creating Stores from Array data easier.
7976 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
7977 * @cfg {Array} fields An array of field definition objects, or field name strings.
7978 * @cfg {Array} data The multi-dimensional array of data
7980 * @param {Object} config
7982 Roo.data.SimpleStore = function(config){
7983 Roo.data.SimpleStore.superclass.constructor.call(this, {
7985 reader: new Roo.data.ArrayReader({
7988 Roo.data.Record.create(config.fields)
7990 proxy : new Roo.data.MemoryProxy(config.data)
7994 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
7996 * Ext JS Library 1.1.1
7997 * Copyright(c) 2006-2007, Ext JS, LLC.
7999 * Originally Released Under LGPL - original licence link has changed is not relivant.
8002 * <script type="text/javascript">
8007 * @extends Roo.data.Store
8008 * @class Roo.data.JsonStore
8009 * Small helper class to make creating Stores for JSON data easier. <br/>
8011 var store = new Roo.data.JsonStore({
8012 url: 'get-images.php',
8014 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
8017 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
8018 * JsonReader and HttpProxy (unless inline data is provided).</b>
8019 * @cfg {Array} fields An array of field definition objects, or field name strings.
8021 * @param {Object} config
8023 Roo.data.JsonStore = function(c){
8024 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
8025 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
8026 reader: new Roo.data.JsonReader(c, c.fields)
8029 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
8031 * Ext JS Library 1.1.1
8032 * Copyright(c) 2006-2007, Ext JS, LLC.
8034 * Originally Released Under LGPL - original licence link has changed is not relivant.
8037 * <script type="text/javascript">
8041 Roo.data.Field = function(config){
8042 if(typeof config == "string"){
8043 config = {name: config};
8045 Roo.apply(this, config);
8051 var st = Roo.data.SortTypes;
8052 // named sortTypes are supported, here we look them up
8053 if(typeof this.sortType == "string"){
8054 this.sortType = st[this.sortType];
8057 // set default sortType for strings and dates
8061 this.sortType = st.asUCString;
8064 this.sortType = st.asDate;
8067 this.sortType = st.none;
8072 var stripRe = /[\$,%]/g;
8074 // prebuilt conversion function for this field, instead of
8075 // switching every time we're reading a value
8077 var cv, dateFormat = this.dateFormat;
8082 cv = function(v){ return v; };
8085 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
8089 return v !== undefined && v !== null && v !== '' ?
8090 parseInt(String(v).replace(stripRe, ""), 10) : '';
8095 return v !== undefined && v !== null && v !== '' ?
8096 parseFloat(String(v).replace(stripRe, ""), 10) : '';
8101 cv = function(v){ return v === true || v === "true" || v == 1; };
8108 if(v instanceof Date){
8112 if(dateFormat == "timestamp"){
8113 return new Date(v*1000);
8115 return Date.parseDate(v, dateFormat);
8117 var parsed = Date.parse(v);
8118 return parsed ? new Date(parsed) : null;
8127 Roo.data.Field.prototype = {
8135 * Ext JS Library 1.1.1
8136 * Copyright(c) 2006-2007, Ext JS, LLC.
8138 * Originally Released Under LGPL - original licence link has changed is not relivant.
8141 * <script type="text/javascript">
8144 // Base class for reading structured data from a data source. This class is intended to be
8145 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
8148 * @class Roo.data.DataReader
8149 * Base class for reading structured data from a data source. This class is intended to be
8150 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
8153 Roo.data.DataReader = function(meta, recordType){
8157 this.recordType = recordType instanceof Array ?
8158 Roo.data.Record.create(recordType) : recordType;
8161 Roo.data.DataReader.prototype = {
8163 * Create an empty record
8164 * @param {Object} data (optional) - overlay some values
8165 * @return {Roo.data.Record} record created.
8167 newRow : function(d) {
8169 this.recordType.prototype.fields.each(function(c) {
8171 case 'int' : da[c.name] = 0; break;
8172 case 'date' : da[c.name] = new Date(); break;
8173 case 'float' : da[c.name] = 0.0; break;
8174 case 'boolean' : da[c.name] = false; break;
8175 default : da[c.name] = ""; break;
8179 return new this.recordType(Roo.apply(da, d));
8184 * Ext JS Library 1.1.1
8185 * Copyright(c) 2006-2007, Ext JS, LLC.
8187 * Originally Released Under LGPL - original licence link has changed is not relivant.
8190 * <script type="text/javascript">
8194 * @class Roo.data.DataProxy
8195 * @extends Roo.data.Observable
8196 * This class is an abstract base class for implementations which provide retrieval of
8197 * unformatted data objects.<br>
8199 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
8200 * (of the appropriate type which knows how to parse the data object) to provide a block of
8201 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
8203 * Custom implementations must implement the load method as described in
8204 * {@link Roo.data.HttpProxy#load}.
8206 Roo.data.DataProxy = function(){
8210 * Fires before a network request is made to retrieve a data object.
8211 * @param {Object} This DataProxy object.
8212 * @param {Object} params The params parameter to the load function.
8217 * Fires before the load method's callback is called.
8218 * @param {Object} This DataProxy object.
8219 * @param {Object} o The data object.
8220 * @param {Object} arg The callback argument object passed to the load function.
8224 * @event loadexception
8225 * Fires if an Exception occurs during data retrieval.
8226 * @param {Object} This DataProxy object.
8227 * @param {Object} o The data object.
8228 * @param {Object} arg The callback argument object passed to the load function.
8229 * @param {Object} e The Exception.
8231 loadexception : true
8233 Roo.data.DataProxy.superclass.constructor.call(this);
8236 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
8239 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
8243 * Ext JS Library 1.1.1
8244 * Copyright(c) 2006-2007, Ext JS, LLC.
8246 * Originally Released Under LGPL - original licence link has changed is not relivant.
8249 * <script type="text/javascript">
8252 * @class Roo.data.MemoryProxy
8253 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
8254 * to the Reader when its load method is called.
8256 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
8258 Roo.data.MemoryProxy = function(data){
8262 Roo.data.MemoryProxy.superclass.constructor.call(this);
8266 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
8268 * Load data from the requested source (in this case an in-memory
8269 * data object passed to the constructor), read the data object into
8270 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
8271 * process that block using the passed callback.
8272 * @param {Object} params This parameter is not used by the MemoryProxy class.
8273 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8274 * object into a block of Roo.data.Records.
8275 * @param {Function} callback The function into which to pass the block of Roo.data.records.
8276 * The function must be passed <ul>
8277 * <li>The Record block object</li>
8278 * <li>The "arg" argument from the load function</li>
8279 * <li>A boolean success indicator</li>
8281 * @param {Object} scope The scope in which to call the callback
8282 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8284 load : function(params, reader, callback, scope, arg){
8285 params = params || {};
8288 result = reader.readRecords(this.data);
8290 this.fireEvent("loadexception", this, arg, null, e);
8291 callback.call(scope, null, arg, false);
8294 callback.call(scope, result, arg, true);
8298 update : function(params, records){
8303 * Ext JS Library 1.1.1
8304 * Copyright(c) 2006-2007, Ext JS, LLC.
8306 * Originally Released Under LGPL - original licence link has changed is not relivant.
8309 * <script type="text/javascript">
8312 * @class Roo.data.HttpProxy
8313 * @extends Roo.data.DataProxy
8314 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
8315 * configured to reference a certain URL.<br><br>
8317 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
8318 * from which the running page was served.<br><br>
8320 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
8322 * Be aware that to enable the browser to parse an XML document, the server must set
8323 * the Content-Type header in the HTTP response to "text/xml".
8325 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
8326 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
8327 * will be used to make the request.
8329 Roo.data.HttpProxy = function(conn){
8330 Roo.data.HttpProxy.superclass.constructor.call(this);
8331 // is conn a conn config or a real conn?
8333 this.useAjax = !conn || !conn.events;
8337 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
8338 // thse are take from connection...
8341 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
8344 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
8345 * extra parameters to each request made by this object. (defaults to undefined)
8348 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
8349 * to each request made by this object. (defaults to undefined)
8352 * @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)
8355 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
8358 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
8364 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
8368 * Return the {@link Roo.data.Connection} object being used by this Proxy.
8369 * @return {Connection} The Connection object. This object may be used to subscribe to events on
8370 * a finer-grained basis than the DataProxy events.
8372 getConnection : function(){
8373 return this.useAjax ? Roo.Ajax : this.conn;
8377 * Load data from the configured {@link Roo.data.Connection}, read the data object into
8378 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
8379 * process that block using the passed callback.
8380 * @param {Object} params An object containing properties which are to be used as HTTP parameters
8381 * for the request to the remote server.
8382 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8383 * object into a block of Roo.data.Records.
8384 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
8385 * The function must be passed <ul>
8386 * <li>The Record block object</li>
8387 * <li>The "arg" argument from the load function</li>
8388 * <li>A boolean success indicator</li>
8390 * @param {Object} scope The scope in which to call the callback
8391 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8393 load : function(params, reader, callback, scope, arg){
8394 if(this.fireEvent("beforeload", this, params) !== false){
8396 params : params || {},
8398 callback : callback,
8403 callback : this.loadResponse,
8407 Roo.applyIf(o, this.conn);
8408 if(this.activeRequest){
8409 Roo.Ajax.abort(this.activeRequest);
8411 this.activeRequest = Roo.Ajax.request(o);
8413 this.conn.request(o);
8416 callback.call(scope||this, null, arg, false);
8421 loadResponse : function(o, success, response){
8422 delete this.activeRequest;
8424 this.fireEvent("loadexception", this, o, response);
8425 o.request.callback.call(o.request.scope, null, o.request.arg, false);
8430 result = o.reader.read(response);
8432 this.fireEvent("loadexception", this, o, response, e);
8433 o.request.callback.call(o.request.scope, null, o.request.arg, false);
8437 this.fireEvent("load", this, o, o.request.arg);
8438 o.request.callback.call(o.request.scope, result, o.request.arg, true);
8442 update : function(dataSet){
8447 updateResponse : function(dataSet){
8452 * Ext JS Library 1.1.1
8453 * Copyright(c) 2006-2007, Ext JS, LLC.
8455 * Originally Released Under LGPL - original licence link has changed is not relivant.
8458 * <script type="text/javascript">
8462 * @class Roo.data.ScriptTagProxy
8463 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
8464 * other than the originating domain of the running page.<br><br>
8466 * <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
8467 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
8469 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
8470 * source code that is used as the source inside a <script> tag.<br><br>
8472 * In order for the browser to process the returned data, the server must wrap the data object
8473 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
8474 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
8475 * depending on whether the callback name was passed:
8478 boolean scriptTag = false;
8479 String cb = request.getParameter("callback");
8482 response.setContentType("text/javascript");
8484 response.setContentType("application/x-json");
8486 Writer out = response.getWriter();
8488 out.write(cb + "(");
8490 out.print(dataBlock.toJsonString());
8497 * @param {Object} config A configuration object.
8499 Roo.data.ScriptTagProxy = function(config){
8500 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
8501 Roo.apply(this, config);
8502 this.head = document.getElementsByTagName("head")[0];
8505 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
8507 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
8509 * @cfg {String} url The URL from which to request the data object.
8512 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
8516 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
8517 * the server the name of the callback function set up by the load call to process the returned data object.
8518 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
8519 * javascript output which calls this named function passing the data object as its only parameter.
8521 callbackParam : "callback",
8523 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
8524 * name to the request.
8529 * Load data from the configured URL, read the data object into
8530 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
8531 * process that block using the passed callback.
8532 * @param {Object} params An object containing properties which are to be used as HTTP parameters
8533 * for the request to the remote server.
8534 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8535 * object into a block of Roo.data.Records.
8536 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
8537 * The function must be passed <ul>
8538 * <li>The Record block object</li>
8539 * <li>The "arg" argument from the load function</li>
8540 * <li>A boolean success indicator</li>
8542 * @param {Object} scope The scope in which to call the callback
8543 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8545 load : function(params, reader, callback, scope, arg){
8546 if(this.fireEvent("beforeload", this, params) !== false){
8548 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
8551 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
8553 url += "&_dc=" + (new Date().getTime());
8555 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
8558 cb : "stcCallback"+transId,
8559 scriptId : "stcScript"+transId,
8563 callback : callback,
8569 window[trans.cb] = function(o){
8570 conn.handleResponse(o, trans);
8573 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
8575 if(this.autoAbort !== false){
8579 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
8581 var script = document.createElement("script");
8582 script.setAttribute("src", url);
8583 script.setAttribute("type", "text/javascript");
8584 script.setAttribute("id", trans.scriptId);
8585 this.head.appendChild(script);
8589 callback.call(scope||this, null, arg, false);
8594 isLoading : function(){
8595 return this.trans ? true : false;
8599 * Abort the current server request.
8602 if(this.isLoading()){
8603 this.destroyTrans(this.trans);
8608 destroyTrans : function(trans, isLoaded){
8609 this.head.removeChild(document.getElementById(trans.scriptId));
8610 clearTimeout(trans.timeoutId);
8612 window[trans.cb] = undefined;
8614 delete window[trans.cb];
8617 // if hasn't been loaded, wait for load to remove it to prevent script error
8618 window[trans.cb] = function(){
8619 window[trans.cb] = undefined;
8621 delete window[trans.cb];
8628 handleResponse : function(o, trans){
8630 this.destroyTrans(trans, true);
8633 result = trans.reader.readRecords(o);
8635 this.fireEvent("loadexception", this, o, trans.arg, e);
8636 trans.callback.call(trans.scope||window, null, trans.arg, false);
8639 this.fireEvent("load", this, o, trans.arg);
8640 trans.callback.call(trans.scope||window, result, trans.arg, true);
8644 handleFailure : function(trans){
8646 this.destroyTrans(trans, false);
8647 this.fireEvent("loadexception", this, null, trans.arg);
8648 trans.callback.call(trans.scope||window, null, trans.arg, false);
8652 * Ext JS Library 1.1.1
8653 * Copyright(c) 2006-2007, Ext JS, LLC.
8655 * Originally Released Under LGPL - original licence link has changed is not relivant.
8658 * <script type="text/javascript">
8662 * @class Roo.data.JsonReader
8663 * @extends Roo.data.DataReader
8664 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
8665 * based on mappings in a provided Roo.data.Record constructor.
8667 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
8668 * in the reply previously.
8673 var RecordDef = Roo.data.Record.create([
8674 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
8675 {name: 'occupation'} // This field will use "occupation" as the mapping.
8677 var myReader = new Roo.data.JsonReader({
8678 totalProperty: "results", // The property which contains the total dataset size (optional)
8679 root: "rows", // The property which contains an Array of row objects
8680 id: "id" // The property within each row object that provides an ID for the record (optional)
8684 * This would consume a JSON file like this:
8686 { 'results': 2, 'rows': [
8687 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
8688 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
8691 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
8692 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
8693 * paged from the remote server.
8694 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
8695 * @cfg {String} root name of the property which contains the Array of row objects.
8696 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
8698 * Create a new JsonReader
8699 * @param {Object} meta Metadata configuration options
8700 * @param {Object} recordType Either an Array of field definition objects,
8701 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
8703 Roo.data.JsonReader = function(meta, recordType){
8706 // set some defaults:
8708 totalProperty: 'total',
8709 successProperty : 'success',
8714 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
8716 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
8719 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
8720 * Used by Store query builder to append _requestMeta to params.
8723 metaFromRemote : false,
8725 * This method is only used by a DataProxy which has retrieved data from a remote server.
8726 * @param {Object} response The XHR object which contains the JSON data in its responseText.
8727 * @return {Object} data A data block which is used by an Roo.data.Store object as
8728 * a cache of Roo.data.Records.
8730 read : function(response){
8731 var json = response.responseText;
8733 var o = /* eval:var:o */ eval("("+json+")");
8735 throw {message: "JsonReader.read: Json object not found"};
8741 this.metaFromRemote = true;
8742 this.meta = o.metaData;
8743 this.recordType = Roo.data.Record.create(o.metaData.fields);
8744 this.onMetaChange(this.meta, this.recordType, o);
8746 return this.readRecords(o);
8749 // private function a store will implement
8750 onMetaChange : function(meta, recordType, o){
8757 simpleAccess: function(obj, subsc) {
8764 getJsonAccessor: function(){
8766 return function(expr) {
8768 return(re.test(expr))
8769 ? new Function("obj", "return obj." + expr)
8779 * Create a data block containing Roo.data.Records from an XML document.
8780 * @param {Object} o An object which contains an Array of row objects in the property specified
8781 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
8782 * which contains the total size of the dataset.
8783 * @return {Object} data A data block which is used by an Roo.data.Store object as
8784 * a cache of Roo.data.Records.
8786 readRecords : function(o){
8788 * After any data loads, the raw JSON data is available for further custom processing.
8792 var s = this.meta, Record = this.recordType,
8793 f = Record.prototype.fields, fi = f.items, fl = f.length;
8795 // Generate extraction functions for the totalProperty, the root, the id, and for each field
8797 if(s.totalProperty) {
8798 this.getTotal = this.getJsonAccessor(s.totalProperty);
8800 if(s.successProperty) {
8801 this.getSuccess = this.getJsonAccessor(s.successProperty);
8803 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
8805 var g = this.getJsonAccessor(s.id);
8806 this.getId = function(rec) {
8808 return (r === undefined || r === "") ? null : r;
8811 this.getId = function(){return null;};
8814 for(var jj = 0; jj < fl; jj++){
8816 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
8817 this.ef[jj] = this.getJsonAccessor(map);
8821 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
8822 if(s.totalProperty){
8823 var vt = parseInt(this.getTotal(o), 10);
8828 if(s.successProperty){
8829 var vs = this.getSuccess(o);
8830 if(vs === false || vs === 'false'){
8835 for(var i = 0; i < c; i++){
8838 var id = this.getId(n);
8839 for(var j = 0; j < fl; j++){
8841 var v = this.ef[j](n);
8843 Roo.log('missing convert for ' + f.name);
8847 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
8849 var record = new Record(values, id);
8851 records[i] = record;
8857 totalRecords : totalRecords
8862 * Ext JS Library 1.1.1
8863 * Copyright(c) 2006-2007, Ext JS, LLC.
8865 * Originally Released Under LGPL - original licence link has changed is not relivant.
8868 * <script type="text/javascript">
8872 * @class Roo.data.ArrayReader
8873 * @extends Roo.data.DataReader
8874 * Data reader class to create an Array of Roo.data.Record objects from an Array.
8875 * Each element of that Array represents a row of data fields. The
8876 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
8877 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
8881 var RecordDef = Roo.data.Record.create([
8882 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
8883 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
8885 var myReader = new Roo.data.ArrayReader({
8886 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
8890 * This would consume an Array like this:
8892 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
8894 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
8896 * Create a new JsonReader
8897 * @param {Object} meta Metadata configuration options.
8898 * @param {Object} recordType Either an Array of field definition objects
8899 * as specified to {@link Roo.data.Record#create},
8900 * or an {@link Roo.data.Record} object
8901 * created using {@link Roo.data.Record#create}.
8903 Roo.data.ArrayReader = function(meta, recordType){
8904 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
8907 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
8909 * Create a data block containing Roo.data.Records from an XML document.
8910 * @param {Object} o An Array of row objects which represents the dataset.
8911 * @return {Object} data A data block which is used by an Roo.data.Store object as
8912 * a cache of Roo.data.Records.
8914 readRecords : function(o){
8915 var sid = this.meta ? this.meta.id : null;
8916 var recordType = this.recordType, fields = recordType.prototype.fields;
8919 for(var i = 0; i < root.length; i++){
8922 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
8923 for(var j = 0, jlen = fields.length; j < jlen; j++){
8924 var f = fields.items[j];
8925 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
8926 var v = n[k] !== undefined ? n[k] : f.defaultValue;
8930 var record = new recordType(values, id);
8932 records[records.length] = record;
8936 totalRecords : records.length
8945 * @class Roo.bootstrap.ComboBox
8946 * @extends Roo.bootstrap.TriggerField
8947 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
8948 * @cfg {Boolean} append (true|false) default false
8950 * Create a new ComboBox.
8951 * @param {Object} config Configuration options
8953 Roo.bootstrap.ComboBox = function(config){
8954 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
8958 * Fires when the dropdown list is expanded
8959 * @param {Roo.bootstrap.ComboBox} combo This combo box
8964 * Fires when the dropdown list is collapsed
8965 * @param {Roo.bootstrap.ComboBox} combo This combo box
8969 * @event beforeselect
8970 * Fires before a list item is selected. Return false to cancel the selection.
8971 * @param {Roo.bootstrap.ComboBox} combo This combo box
8972 * @param {Roo.data.Record} record The data record returned from the underlying store
8973 * @param {Number} index The index of the selected item in the dropdown list
8975 'beforeselect' : true,
8978 * Fires when a list item is selected
8979 * @param {Roo.bootstrap.ComboBox} combo This combo box
8980 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
8981 * @param {Number} index The index of the selected item in the dropdown list
8985 * @event beforequery
8986 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
8987 * The event object passed has these properties:
8988 * @param {Roo.bootstrap.ComboBox} combo This combo box
8989 * @param {String} query The query
8990 * @param {Boolean} forceAll true to force "all" query
8991 * @param {Boolean} cancel true to cancel the query
8992 * @param {Object} e The query event object
8994 'beforequery': true,
8997 * Fires when the 'add' icon is pressed (add a listener to enable add button)
8998 * @param {Roo.bootstrap.ComboBox} combo This combo box
9003 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
9004 * @param {Roo.bootstrap.ComboBox} combo This combo box
9005 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
9010 * Fires when the remove value from the combobox array
9011 * @param {Roo.bootstrap.ComboBox} combo This combo box
9018 this.selectedIndex = -1;
9019 if(this.mode == 'local'){
9020 if(config.queryDelay === undefined){
9021 this.queryDelay = 10;
9023 if(config.minChars === undefined){
9029 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
9032 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
9033 * rendering into an Roo.Editor, defaults to false)
9036 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
9037 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
9040 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
9043 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
9044 * the dropdown list (defaults to undefined, with no header element)
9048 * @cfg {String/Roo.Template} tpl The template to use to render the output
9052 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
9054 listWidth: undefined,
9056 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
9057 * mode = 'remote' or 'text' if mode = 'local')
9059 displayField: undefined,
9061 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
9062 * mode = 'remote' or 'value' if mode = 'local').
9063 * Note: use of a valueField requires the user make a selection
9064 * in order for a value to be mapped.
9066 valueField: undefined,
9070 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
9071 * field's data value (defaults to the underlying DOM element's name)
9073 hiddenName: undefined,
9075 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
9079 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
9081 selectedClass: 'active',
9084 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
9088 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
9089 * anchor positions (defaults to 'tl-bl')
9091 listAlign: 'tl-bl?',
9093 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
9097 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
9098 * query specified by the allQuery config option (defaults to 'query')
9100 triggerAction: 'query',
9102 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
9103 * (defaults to 4, does not apply if editable = false)
9107 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
9108 * delay (typeAheadDelay) if it matches a known value (defaults to false)
9112 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
9113 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
9117 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
9118 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
9122 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
9123 * when editable = true (defaults to false)
9125 selectOnFocus:false,
9127 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
9129 queryParam: 'query',
9131 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
9132 * when mode = 'remote' (defaults to 'Loading...')
9134 loadingText: 'Loading...',
9136 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
9140 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
9144 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
9145 * traditional select (defaults to true)
9149 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
9153 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
9157 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
9158 * listWidth has a higher value)
9162 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
9163 * allow the user to set arbitrary text into the field (defaults to false)
9165 forceSelection:false,
9167 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
9168 * if typeAhead = true (defaults to 250)
9170 typeAheadDelay : 250,
9172 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
9173 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
9175 valueNotFoundText : undefined,
9177 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
9182 * @cfg {Boolean} disableClear Disable showing of clear button.
9184 disableClear : false,
9186 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
9188 alwaysQuery : false,
9191 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
9205 // element that contains real text value.. (when hidden is used..)
9208 initEvents: function(){
9211 throw "can not find store for combo";
9213 this.store = Roo.factory(this.store, Roo.data);
9217 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
9220 if(this.hiddenName){
9222 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
9224 this.hiddenField.dom.value =
9225 this.hiddenValue !== undefined ? this.hiddenValue :
9226 this.value !== undefined ? this.value : '';
9228 // prevent input submission
9229 this.el.dom.removeAttribute('name');
9230 this.hiddenField.dom.setAttribute('name', this.hiddenName);
9235 // this.el.dom.setAttribute('autocomplete', 'off');
9238 var cls = 'x-combo-list';
9239 this.list = this.el.select('ul.dropdown-menu',true).first();
9241 //this.list = new Roo.Layer({
9242 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
9245 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
9246 this.list.setWidth(lw);
9248 this.list.on('mouseover', this.onViewOver, this);
9249 this.list.on('mousemove', this.onViewMove, this);
9251 this.list.on('scroll', this.onViewScroll, this);
9254 this.list.swallowEvent('mousewheel');
9255 this.assetHeight = 0;
9258 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
9259 this.assetHeight += this.header.getHeight();
9262 this.innerList = this.list.createChild({cls:cls+'-inner'});
9263 this.innerList.on('mouseover', this.onViewOver, this);
9264 this.innerList.on('mousemove', this.onViewMove, this);
9265 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
9267 if(this.allowBlank && !this.pageSize && !this.disableClear){
9268 this.footer = this.list.createChild({cls:cls+'-ft'});
9269 this.pageTb = new Roo.Toolbar(this.footer);
9273 this.footer = this.list.createChild({cls:cls+'-ft'});
9274 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
9275 {pageSize: this.pageSize});
9279 if (this.pageTb && this.allowBlank && !this.disableClear) {
9281 this.pageTb.add(new Roo.Toolbar.Fill(), {
9282 cls: 'x-btn-icon x-btn-clear',
9288 _this.onSelect(false, -1);
9293 this.assetHeight += this.footer.getHeight();
9298 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
9301 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
9302 singleSelect:true, store: this.store, selectedClass: this.selectedClass
9304 //this.view.wrapEl.setDisplayed(false);
9305 this.view.on('click', this.onViewClick, this);
9309 this.store.on('beforeload', this.onBeforeLoad, this);
9310 this.store.on('load', this.onLoad, this);
9311 this.store.on('loadexception', this.onLoadException, this);
9314 this.resizer = new Roo.Resizable(this.list, {
9315 pinned:true, handles:'se'
9317 this.resizer.on('resize', function(r, w, h){
9318 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
9320 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
9321 this.restrictHeight();
9323 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
9327 this.editable = true;
9328 this.setEditable(false);
9333 if (typeof(this.events.add.listeners) != 'undefined') {
9335 this.addicon = this.wrap.createChild(
9336 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
9338 this.addicon.on('click', function(e) {
9339 this.fireEvent('add', this);
9342 if (typeof(this.events.edit.listeners) != 'undefined') {
9344 this.editicon = this.wrap.createChild(
9345 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
9347 this.editicon.setStyle('margin-left', '40px');
9349 this.editicon.on('click', function(e) {
9351 // we fire even if inothing is selected..
9352 this.fireEvent('edit', this, this.lastData );
9358 this.keyNav = new Roo.KeyNav(this.inputEl(), {
9360 this.inKeyMode = true;
9364 "down" : function(e){
9365 if(!this.isExpanded()){
9366 this.onTriggerClick();
9368 this.inKeyMode = true;
9373 "enter" : function(e){
9378 "esc" : function(e){
9382 "tab" : function(e){
9385 if(this.fireEvent("specialkey", this, e)){
9386 this.onViewClick(false);
9394 doRelay : function(foo, bar, hname){
9395 if(hname == 'down' || this.scope.isExpanded()){
9396 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
9405 this.queryDelay = Math.max(this.queryDelay || 10,
9406 this.mode == 'local' ? 10 : 250);
9409 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
9412 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
9414 if(this.editable !== false){
9415 this.inputEl().on("keyup", this.onKeyUp, this);
9417 if(this.forceSelection){
9418 this.inputEl().on('blur', this.doForce, this);
9422 this.choices = this.el.select('ul.select2-choices', true).first();
9423 this.searchField = this.el.select('ul li.select2-search-field', true).first();
9427 onDestroy : function(){
9429 this.view.setStore(null);
9430 this.view.el.removeAllListeners();
9431 this.view.el.remove();
9432 this.view.purgeListeners();
9435 this.list.dom.innerHTML = '';
9438 this.store.un('beforeload', this.onBeforeLoad, this);
9439 this.store.un('load', this.onLoad, this);
9440 this.store.un('loadexception', this.onLoadException, this);
9442 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
9446 fireKey : function(e){
9447 if(e.isNavKeyPress() && !this.list.isVisible()){
9448 this.fireEvent("specialkey", this, e);
9453 onResize: function(w, h){
9454 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
9456 // if(typeof w != 'number'){
9457 // // we do not handle it!?!?
9460 // var tw = this.trigger.getWidth();
9461 // // tw += this.addicon ? this.addicon.getWidth() : 0;
9462 // // tw += this.editicon ? this.editicon.getWidth() : 0;
9464 // this.inputEl().setWidth( this.adjustWidth('input', x));
9466 // //this.trigger.setStyle('left', x+'px');
9468 // if(this.list && this.listWidth === undefined){
9469 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
9470 // this.list.setWidth(lw);
9471 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
9479 * Allow or prevent the user from directly editing the field text. If false is passed,
9480 * the user will only be able to select from the items defined in the dropdown list. This method
9481 * is the runtime equivalent of setting the 'editable' config option at config time.
9482 * @param {Boolean} value True to allow the user to directly edit the field text
9484 setEditable : function(value){
9485 if(value == this.editable){
9488 this.editable = value;
9490 this.inputEl().dom.setAttribute('readOnly', true);
9491 this.inputEl().on('mousedown', this.onTriggerClick, this);
9492 this.inputEl().addClass('x-combo-noedit');
9494 this.inputEl().dom.setAttribute('readOnly', false);
9495 this.inputEl().un('mousedown', this.onTriggerClick, this);
9496 this.inputEl().removeClass('x-combo-noedit');
9502 onBeforeLoad : function(combo,opts){
9507 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
9509 this.restrictHeight();
9510 this.selectedIndex = -1;
9514 onLoad : function(){
9516 this.hasQuery = false;
9522 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
9523 this.loading.hide();
9526 if(this.store.getCount() > 0){
9528 this.restrictHeight();
9529 if(this.lastQuery == this.allQuery){
9531 this.inputEl().dom.select();
9533 if(!this.selectByValue(this.value, true)){
9534 this.select(0, true);
9538 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
9539 this.taTask.delay(this.typeAheadDelay);
9543 this.onEmptyResults();
9549 onLoadException : function()
9551 this.hasQuery = false;
9553 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
9554 this.loading.hide();
9558 Roo.log(this.store.reader.jsonData);
9559 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
9561 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
9567 onTypeAhead : function(){
9568 if(this.store.getCount() > 0){
9569 var r = this.store.getAt(0);
9570 var newValue = r.data[this.displayField];
9571 var len = newValue.length;
9572 var selStart = this.getRawValue().length;
9574 if(selStart != len){
9575 this.setRawValue(newValue);
9576 this.selectText(selStart, newValue.length);
9582 onSelect : function(record, index){
9584 if(this.fireEvent('beforeselect', this, record, index) !== false){
9586 this.setFromData(index > -1 ? record.data : false);
9589 this.fireEvent('select', this, record, index);
9594 * Returns the currently selected field value or empty string if no value is set.
9595 * @return {String} value The selected value
9597 getValue : function(){
9600 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
9603 if(this.valueField){
9604 return typeof this.value != 'undefined' ? this.value : '';
9606 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
9611 * Clears any text/value currently set in the field
9613 clearValue : function(){
9614 if(this.hiddenField){
9615 this.hiddenField.dom.value = '';
9618 this.setRawValue('');
9619 this.lastSelectionText = '';
9624 * Sets the specified value into the field. If the value finds a match, the corresponding record text
9625 * will be displayed in the field. If the value does not match the data value of an existing item,
9626 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
9627 * Otherwise the field will be blank (although the value will still be set).
9628 * @param {String} value The value to match
9630 setValue : function(v){
9637 if(this.valueField){
9638 var r = this.findRecord(this.valueField, v);
9640 text = r.data[this.displayField];
9641 }else if(this.valueNotFoundText !== undefined){
9642 text = this.valueNotFoundText;
9645 this.lastSelectionText = text;
9646 if(this.hiddenField){
9647 this.hiddenField.dom.value = v;
9649 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
9653 * @property {Object} the last set data for the element
9658 * Sets the value of the field based on a object which is related to the record format for the store.
9659 * @param {Object} value the value to set as. or false on reset?
9661 setFromData : function(o){
9668 var dv = ''; // display value
9669 var vv = ''; // value value..
9671 if (this.displayField) {
9672 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
9674 // this is an error condition!!!
9675 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
9678 if(this.valueField){
9679 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
9682 if(this.hiddenField){
9683 this.hiddenField.dom.value = vv;
9685 this.lastSelectionText = dv;
9686 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
9690 // no hidden field.. - we store the value in 'value', but still display
9691 // display field!!!!
9692 this.lastSelectionText = dv;
9693 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
9700 // overridden so that last data is reset..
9701 this.setValue(this.originalValue);
9702 this.clearInvalid();
9703 this.lastData = false;
9705 this.view.clearSelections();
9709 findRecord : function(prop, value){
9711 if(this.store.getCount() > 0){
9712 this.store.each(function(r){
9713 if(r.data[prop] == value){
9725 // returns hidden if it's set..
9726 if (!this.rendered) {return ''};
9727 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
9731 onViewMove : function(e, t){
9732 this.inKeyMode = false;
9736 onViewOver : function(e, t){
9737 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
9740 var item = this.view.findItemFromChild(t);
9742 var index = this.view.indexOf(item);
9743 this.select(index, false);
9748 onViewClick : function(doFocus)
9750 var index = this.view.getSelectedIndexes()[0];
9751 var r = this.store.getAt(index);
9753 this.onSelect(r, index);
9755 if(doFocus !== false && !this.blockFocus){
9756 this.inputEl().focus();
9761 restrictHeight : function(){
9762 //this.innerList.dom.style.height = '';
9763 //var inner = this.innerList.dom;
9764 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
9765 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
9766 //this.list.beginUpdate();
9767 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
9768 this.list.alignTo(this.inputEl(), this.listAlign);
9769 //this.list.endUpdate();
9773 onEmptyResults : function(){
9778 * Returns true if the dropdown list is expanded, else false.
9780 isExpanded : function(){
9781 return this.list.isVisible();
9785 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
9786 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
9787 * @param {String} value The data value of the item to select
9788 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
9789 * selected item if it is not currently in view (defaults to true)
9790 * @return {Boolean} True if the value matched an item in the list, else false
9792 selectByValue : function(v, scrollIntoView){
9793 if(v !== undefined && v !== null){
9794 var r = this.findRecord(this.valueField || this.displayField, v);
9796 this.select(this.store.indexOf(r), scrollIntoView);
9804 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
9805 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
9806 * @param {Number} index The zero-based index of the list item to select
9807 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
9808 * selected item if it is not currently in view (defaults to true)
9810 select : function(index, scrollIntoView){
9811 this.selectedIndex = index;
9812 this.view.select(index);
9813 if(scrollIntoView !== false){
9814 var el = this.view.getNode(index);
9816 //this.innerList.scrollChildIntoView(el, false);
9823 selectNext : function(){
9824 var ct = this.store.getCount();
9826 if(this.selectedIndex == -1){
9828 }else if(this.selectedIndex < ct-1){
9829 this.select(this.selectedIndex+1);
9835 selectPrev : function(){
9836 var ct = this.store.getCount();
9838 if(this.selectedIndex == -1){
9840 }else if(this.selectedIndex != 0){
9841 this.select(this.selectedIndex-1);
9847 onKeyUp : function(e){
9848 if(this.editable !== false && !e.isSpecialKey()){
9849 this.lastKey = e.getKey();
9850 this.dqTask.delay(this.queryDelay);
9855 validateBlur : function(){
9856 return !this.list || !this.list.isVisible();
9860 initQuery : function(){
9861 this.doQuery(this.getRawValue());
9865 doForce : function(){
9866 if(this.inputEl().dom.value.length > 0){
9867 this.inputEl().dom.value =
9868 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
9874 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
9875 * query allowing the query action to be canceled if needed.
9876 * @param {String} query The SQL query to execute
9877 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
9878 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
9879 * saved in the current store (defaults to false)
9881 doQuery : function(q, forceAll){
9883 if(q === undefined || q === null){
9892 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
9897 forceAll = qe.forceAll;
9898 if(forceAll === true || (q.length >= this.minChars)){
9900 this.hasQuery = true;
9902 if(this.lastQuery != q || this.alwaysQuery){
9904 if(this.mode == 'local'){
9905 this.selectedIndex = -1;
9907 this.store.clearFilter();
9909 this.store.filter(this.displayField, q);
9913 this.store.baseParams[this.queryParam] = q;
9915 var options = {params : this.getParams(q)};
9919 options.params.start = this.page * this.pageSize;
9922 this.store.load(options);
9926 this.selectedIndex = -1;
9931 this.loadNext = false;
9935 getParams : function(q){
9937 //p[this.queryParam] = q;
9941 p.limit = this.pageSize;
9947 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
9949 collapse : function(){
9950 if(!this.isExpanded()){
9955 Roo.get(document).un('mousedown', this.collapseIf, this);
9956 Roo.get(document).un('mousewheel', this.collapseIf, this);
9957 if (!this.editable) {
9958 Roo.get(document).un('keydown', this.listKeyPress, this);
9960 this.fireEvent('collapse', this);
9964 collapseIf : function(e){
9965 var in_combo = e.within(this.el);
9966 var in_list = e.within(this.list);
9968 if (in_combo || in_list) {
9969 //e.stopPropagation();
9978 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
9980 expand : function(){
9982 if(this.isExpanded() || !this.hasFocus){
9986 this.list.alignTo(this.inputEl(), this.listAlign);
9988 Roo.get(document).on('mousedown', this.collapseIf, this);
9989 Roo.get(document).on('mousewheel', this.collapseIf, this);
9990 if (!this.editable) {
9991 Roo.get(document).on('keydown', this.listKeyPress, this);
9994 this.fireEvent('expand', this);
9998 // Implements the default empty TriggerField.onTriggerClick function
9999 onTriggerClick : function()
10001 Roo.log('trigger click');
10008 this.loadNext = false;
10010 if(this.isExpanded()){
10012 if (!this.blockFocus) {
10013 this.inputEl().focus();
10017 this.hasFocus = true;
10018 if(this.triggerAction == 'all') {
10019 this.doQuery(this.allQuery, true);
10021 this.doQuery(this.getRawValue());
10023 if (!this.blockFocus) {
10024 this.inputEl().focus();
10028 listKeyPress : function(e)
10030 //Roo.log('listkeypress');
10031 // scroll to first matching element based on key pres..
10032 if (e.isSpecialKey()) {
10035 var k = String.fromCharCode(e.getKey()).toUpperCase();
10038 var csel = this.view.getSelectedNodes();
10039 var cselitem = false;
10041 var ix = this.view.indexOf(csel[0]);
10042 cselitem = this.store.getAt(ix);
10043 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
10049 this.store.each(function(v) {
10051 // start at existing selection.
10052 if (cselitem.id == v.id) {
10058 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
10059 match = this.store.indexOf(v);
10065 if (match === false) {
10066 return true; // no more action?
10069 this.view.select(match);
10070 var sn = Roo.get(this.view.getSelectedNodes()[0])
10071 //sn.scrollIntoView(sn.dom.parentNode, false);
10074 onViewScroll : function(e, t){
10076 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
10080 this.hasQuery = true;
10082 this.loading = this.list.select('.loading', true).first();
10084 if(this.loading === null){
10085 this.list.createChild({
10087 cls: 'loading select2-more-results select2-active',
10088 html: 'Loading more results...'
10091 this.loading = this.list.select('.loading', true).first();
10093 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
10095 this.loading.hide();
10098 this.loading.show();
10103 this.loadNext = true;
10105 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
10110 addItem : function(o)
10112 var dv = ''; // display value
10114 if (this.displayField) {
10115 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
10117 // this is an error condition!!!
10118 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
10125 var choice = this.choices.createChild({
10127 cls: 'select2-search-choice',
10136 cls: 'select2-search-choice-close',
10141 }, this.searchField);
10143 var close = choice.select('a.select2-search-choice-close', true).first()
10145 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
10152 this.inputEl().dom.value = '';
10156 onRemoveItem : function(e, _self, o)
10158 e.preventDefault();
10159 var index = this.item.indexOf(o.data) * 1;
10162 Roo.log('not this item?!');
10166 this.item.splice(index, 1);
10171 this.fireEvent('remove', this, e);
10175 syncValue : function()
10177 if(!this.item.length){
10184 Roo.each(this.item, function(i){
10185 if(_this.valueField){
10186 value.push(i[_this.valueField]);
10193 this.value = value.join(',');
10195 if(this.hiddenField){
10196 this.hiddenField.dom.value = this.value;
10200 clearItem : function()
10202 if(!this.multiple){
10208 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
10218 * @cfg {Boolean} grow
10222 * @cfg {Number} growMin
10226 * @cfg {Number} growMax
10236 * Ext JS Library 1.1.1
10237 * Copyright(c) 2006-2007, Ext JS, LLC.
10239 * Originally Released Under LGPL - original licence link has changed is not relivant.
10242 * <script type="text/javascript">
10247 * @extends Roo.util.Observable
10248 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
10249 * This class also supports single and multi selection modes. <br>
10250 * Create a data model bound view:
10252 var store = new Roo.data.Store(...);
10254 var view = new Roo.View({
10256 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
10258 singleSelect: true,
10259 selectedClass: "ydataview-selected",
10263 // listen for node click?
10264 view.on("click", function(vw, index, node, e){
10265 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
10269 dataModel.load("foobar.xml");
10271 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
10273 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
10274 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
10276 * Note: old style constructor is still suported (container, template, config)
10279 * Create a new View
10280 * @param {Object} config The config object
10283 Roo.View = function(config, depreciated_tpl, depreciated_config){
10285 if (typeof(depreciated_tpl) == 'undefined') {
10286 // new way.. - universal constructor.
10287 Roo.apply(this, config);
10288 this.el = Roo.get(this.el);
10291 this.el = Roo.get(config);
10292 this.tpl = depreciated_tpl;
10293 Roo.apply(this, depreciated_config);
10295 this.wrapEl = this.el.wrap().wrap();
10296 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
10299 if(typeof(this.tpl) == "string"){
10300 this.tpl = new Roo.Template(this.tpl);
10302 // support xtype ctors..
10303 this.tpl = new Roo.factory(this.tpl, Roo);
10307 this.tpl.compile();
10315 * @event beforeclick
10316 * Fires before a click is processed. Returns false to cancel the default action.
10317 * @param {Roo.View} this
10318 * @param {Number} index The index of the target node
10319 * @param {HTMLElement} node The target node
10320 * @param {Roo.EventObject} e The raw event object
10322 "beforeclick" : true,
10325 * Fires when a template node is clicked.
10326 * @param {Roo.View} this
10327 * @param {Number} index The index of the target node
10328 * @param {HTMLElement} node The target node
10329 * @param {Roo.EventObject} e The raw event object
10334 * Fires when a template node is double clicked.
10335 * @param {Roo.View} this
10336 * @param {Number} index The index of the target node
10337 * @param {HTMLElement} node The target node
10338 * @param {Roo.EventObject} e The raw event object
10342 * @event contextmenu
10343 * Fires when a template node is right clicked.
10344 * @param {Roo.View} this
10345 * @param {Number} index The index of the target node
10346 * @param {HTMLElement} node The target node
10347 * @param {Roo.EventObject} e The raw event object
10349 "contextmenu" : true,
10351 * @event selectionchange
10352 * Fires when the selected nodes change.
10353 * @param {Roo.View} this
10354 * @param {Array} selections Array of the selected nodes
10356 "selectionchange" : true,
10359 * @event beforeselect
10360 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
10361 * @param {Roo.View} this
10362 * @param {HTMLElement} node The node to be selected
10363 * @param {Array} selections Array of currently selected nodes
10365 "beforeselect" : true,
10367 * @event preparedata
10368 * Fires on every row to render, to allow you to change the data.
10369 * @param {Roo.View} this
10370 * @param {Object} data to be rendered (change this)
10372 "preparedata" : true
10380 "click": this.onClick,
10381 "dblclick": this.onDblClick,
10382 "contextmenu": this.onContextMenu,
10386 this.selections = [];
10388 this.cmp = new Roo.CompositeElementLite([]);
10390 this.store = Roo.factory(this.store, Roo.data);
10391 this.setStore(this.store, true);
10394 if ( this.footer && this.footer.xtype) {
10396 var fctr = this.wrapEl.appendChild(document.createElement("div"));
10398 this.footer.dataSource = this.store
10399 this.footer.container = fctr;
10400 this.footer = Roo.factory(this.footer, Roo);
10401 fctr.insertFirst(this.el);
10403 // this is a bit insane - as the paging toolbar seems to detach the el..
10404 // dom.parentNode.parentNode.parentNode
10405 // they get detached?
10409 Roo.View.superclass.constructor.call(this);
10414 Roo.extend(Roo.View, Roo.util.Observable, {
10417 * @cfg {Roo.data.Store} store Data store to load data from.
10422 * @cfg {String|Roo.Element} el The container element.
10427 * @cfg {String|Roo.Template} tpl The template used by this View
10431 * @cfg {String} dataName the named area of the template to use as the data area
10432 * Works with domtemplates roo-name="name"
10436 * @cfg {String} selectedClass The css class to add to selected nodes
10438 selectedClass : "x-view-selected",
10440 * @cfg {String} emptyText The empty text to show when nothing is loaded.
10445 * @cfg {String} text to display on mask (default Loading)
10449 * @cfg {Boolean} multiSelect Allow multiple selection
10451 multiSelect : false,
10453 * @cfg {Boolean} singleSelect Allow single selection
10455 singleSelect: false,
10458 * @cfg {Boolean} toggleSelect - selecting
10460 toggleSelect : false,
10463 * Returns the element this view is bound to.
10464 * @return {Roo.Element}
10466 getEl : function(){
10467 return this.wrapEl;
10473 * Refreshes the view. - called by datachanged on the store. - do not call directly.
10475 refresh : function(){
10476 Roo.log('refresh');
10479 // if we are using something like 'domtemplate', then
10480 // the what gets used is:
10481 // t.applySubtemplate(NAME, data, wrapping data..)
10482 // the outer template then get' applied with
10483 // the store 'extra data'
10484 // and the body get's added to the
10485 // roo-name="data" node?
10486 // <span class='roo-tpl-{name}'></span> ?????
10490 this.clearSelections();
10491 this.el.update("");
10493 var records = this.store.getRange();
10494 if(records.length < 1) {
10496 // is this valid?? = should it render a template??
10498 this.el.update(this.emptyText);
10502 if (this.dataName) {
10503 this.el.update(t.apply(this.store.meta)); //????
10504 el = this.el.child('.roo-tpl-' + this.dataName);
10507 for(var i = 0, len = records.length; i < len; i++){
10508 var data = this.prepareData(records[i].data, i, records[i]);
10509 this.fireEvent("preparedata", this, data, i, records[i]);
10510 html[html.length] = Roo.util.Format.trim(
10512 t.applySubtemplate(this.dataName, data, this.store.meta) :
10519 el.update(html.join(""));
10520 this.nodes = el.dom.childNodes;
10521 this.updateIndexes(0);
10526 * Function to override to reformat the data that is sent to
10527 * the template for each node.
10528 * DEPRICATED - use the preparedata event handler.
10529 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
10530 * a JSON object for an UpdateManager bound view).
10532 prepareData : function(data, index, record)
10534 this.fireEvent("preparedata", this, data, index, record);
10538 onUpdate : function(ds, record){
10539 Roo.log('on update');
10540 this.clearSelections();
10541 var index = this.store.indexOf(record);
10542 var n = this.nodes[index];
10543 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
10544 n.parentNode.removeChild(n);
10545 this.updateIndexes(index, index);
10551 onAdd : function(ds, records, index)
10553 Roo.log(['on Add', ds, records, index] );
10554 this.clearSelections();
10555 if(this.nodes.length == 0){
10559 var n = this.nodes[index];
10560 for(var i = 0, len = records.length; i < len; i++){
10561 var d = this.prepareData(records[i].data, i, records[i]);
10563 this.tpl.insertBefore(n, d);
10566 this.tpl.append(this.el, d);
10569 this.updateIndexes(index);
10572 onRemove : function(ds, record, index){
10573 Roo.log('onRemove');
10574 this.clearSelections();
10575 var el = this.dataName ?
10576 this.el.child('.roo-tpl-' + this.dataName) :
10579 el.dom.removeChild(this.nodes[index]);
10580 this.updateIndexes(index);
10584 * Refresh an individual node.
10585 * @param {Number} index
10587 refreshNode : function(index){
10588 this.onUpdate(this.store, this.store.getAt(index));
10591 updateIndexes : function(startIndex, endIndex){
10592 var ns = this.nodes;
10593 startIndex = startIndex || 0;
10594 endIndex = endIndex || ns.length - 1;
10595 for(var i = startIndex; i <= endIndex; i++){
10596 ns[i].nodeIndex = i;
10601 * Changes the data store this view uses and refresh the view.
10602 * @param {Store} store
10604 setStore : function(store, initial){
10605 if(!initial && this.store){
10606 this.store.un("datachanged", this.refresh);
10607 this.store.un("add", this.onAdd);
10608 this.store.un("remove", this.onRemove);
10609 this.store.un("update", this.onUpdate);
10610 this.store.un("clear", this.refresh);
10611 this.store.un("beforeload", this.onBeforeLoad);
10612 this.store.un("load", this.onLoad);
10613 this.store.un("loadexception", this.onLoad);
10617 store.on("datachanged", this.refresh, this);
10618 store.on("add", this.onAdd, this);
10619 store.on("remove", this.onRemove, this);
10620 store.on("update", this.onUpdate, this);
10621 store.on("clear", this.refresh, this);
10622 store.on("beforeload", this.onBeforeLoad, this);
10623 store.on("load", this.onLoad, this);
10624 store.on("loadexception", this.onLoad, this);
10632 * onbeforeLoad - masks the loading area.
10635 onBeforeLoad : function(store,opts)
10637 Roo.log('onBeforeLoad');
10639 this.el.update("");
10641 this.el.mask(this.mask ? this.mask : "Loading" );
10643 onLoad : function ()
10650 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
10651 * @param {HTMLElement} node
10652 * @return {HTMLElement} The template node
10654 findItemFromChild : function(node){
10655 var el = this.dataName ?
10656 this.el.child('.roo-tpl-' + this.dataName,true) :
10659 if(!node || node.parentNode == el){
10662 var p = node.parentNode;
10663 while(p && p != el){
10664 if(p.parentNode == el){
10673 onClick : function(e){
10674 var item = this.findItemFromChild(e.getTarget());
10676 var index = this.indexOf(item);
10677 if(this.onItemClick(item, index, e) !== false){
10678 this.fireEvent("click", this, index, item, e);
10681 this.clearSelections();
10686 onContextMenu : function(e){
10687 var item = this.findItemFromChild(e.getTarget());
10689 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
10694 onDblClick : function(e){
10695 var item = this.findItemFromChild(e.getTarget());
10697 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
10701 onItemClick : function(item, index, e)
10703 if(this.fireEvent("beforeclick", this, index, item, e) === false){
10706 if (this.toggleSelect) {
10707 var m = this.isSelected(item) ? 'unselect' : 'select';
10710 _t[m](item, true, false);
10713 if(this.multiSelect || this.singleSelect){
10714 if(this.multiSelect && e.shiftKey && this.lastSelection){
10715 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
10717 this.select(item, this.multiSelect && e.ctrlKey);
10718 this.lastSelection = item;
10720 e.preventDefault();
10726 * Get the number of selected nodes.
10729 getSelectionCount : function(){
10730 return this.selections.length;
10734 * Get the currently selected nodes.
10735 * @return {Array} An array of HTMLElements
10737 getSelectedNodes : function(){
10738 return this.selections;
10742 * Get the indexes of the selected nodes.
10745 getSelectedIndexes : function(){
10746 var indexes = [], s = this.selections;
10747 for(var i = 0, len = s.length; i < len; i++){
10748 indexes.push(s[i].nodeIndex);
10754 * Clear all selections
10755 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
10757 clearSelections : function(suppressEvent){
10758 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
10759 this.cmp.elements = this.selections;
10760 this.cmp.removeClass(this.selectedClass);
10761 this.selections = [];
10762 if(!suppressEvent){
10763 this.fireEvent("selectionchange", this, this.selections);
10769 * Returns true if the passed node is selected
10770 * @param {HTMLElement/Number} node The node or node index
10771 * @return {Boolean}
10773 isSelected : function(node){
10774 var s = this.selections;
10778 node = this.getNode(node);
10779 return s.indexOf(node) !== -1;
10784 * @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
10785 * @param {Boolean} keepExisting (optional) true to keep existing selections
10786 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
10788 select : function(nodeInfo, keepExisting, suppressEvent){
10789 if(nodeInfo instanceof Array){
10791 this.clearSelections(true);
10793 for(var i = 0, len = nodeInfo.length; i < len; i++){
10794 this.select(nodeInfo[i], true, true);
10798 var node = this.getNode(nodeInfo);
10799 if(!node || this.isSelected(node)){
10800 return; // already selected.
10803 this.clearSelections(true);
10805 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
10806 Roo.fly(node).addClass(this.selectedClass);
10807 this.selections.push(node);
10808 if(!suppressEvent){
10809 this.fireEvent("selectionchange", this, this.selections);
10817 * @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
10818 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
10819 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
10821 unselect : function(nodeInfo, keepExisting, suppressEvent)
10823 if(nodeInfo instanceof Array){
10824 Roo.each(this.selections, function(s) {
10825 this.unselect(s, nodeInfo);
10829 var node = this.getNode(nodeInfo);
10830 if(!node || !this.isSelected(node)){
10831 Roo.log("not selected");
10832 return; // not selected.
10836 Roo.each(this.selections, function(s) {
10838 Roo.fly(node).removeClass(this.selectedClass);
10845 this.selections= ns;
10846 this.fireEvent("selectionchange", this, this.selections);
10850 * Gets a template node.
10851 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
10852 * @return {HTMLElement} The node or null if it wasn't found
10854 getNode : function(nodeInfo){
10855 if(typeof nodeInfo == "string"){
10856 return document.getElementById(nodeInfo);
10857 }else if(typeof nodeInfo == "number"){
10858 return this.nodes[nodeInfo];
10864 * Gets a range template nodes.
10865 * @param {Number} startIndex
10866 * @param {Number} endIndex
10867 * @return {Array} An array of nodes
10869 getNodes : function(start, end){
10870 var ns = this.nodes;
10871 start = start || 0;
10872 end = typeof end == "undefined" ? ns.length - 1 : end;
10875 for(var i = start; i <= end; i++){
10879 for(var i = start; i >= end; i--){
10887 * Finds the index of the passed node
10888 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
10889 * @return {Number} The index of the node or -1
10891 indexOf : function(node){
10892 node = this.getNode(node);
10893 if(typeof node.nodeIndex == "number"){
10894 return node.nodeIndex;
10896 var ns = this.nodes;
10897 for(var i = 0, len = ns.length; i < len; i++){
10908 * based on jquery fullcalendar
10912 Roo.bootstrap = Roo.bootstrap || {};
10914 * @class Roo.bootstrap.Calendar
10915 * @extends Roo.bootstrap.Component
10916 * Bootstrap Calendar class
10917 * @cfg {Boolean} loadMask (true|false) default false
10918 * @cfg {Object} header generate the user specific header of the calendar, default false
10921 * Create a new Container
10922 * @param {Object} config The config object
10927 Roo.bootstrap.Calendar = function(config){
10928 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
10932 * Fires when a date is selected
10933 * @param {DatePicker} this
10934 * @param {Date} date The selected date
10938 * @event monthchange
10939 * Fires when the displayed month changes
10940 * @param {DatePicker} this
10941 * @param {Date} date The selected month
10943 'monthchange': true,
10945 * @event evententer
10946 * Fires when mouse over an event
10947 * @param {Calendar} this
10948 * @param {event} Event
10950 'evententer': true,
10952 * @event eventleave
10953 * Fires when the mouse leaves an
10954 * @param {Calendar} this
10957 'eventleave': true,
10959 * @event eventclick
10960 * Fires when the mouse click an
10961 * @param {Calendar} this
10970 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
10973 * @cfg {Number} startDay
10974 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
10982 getAutoCreate : function(){
10985 var fc_button = function(name, corner, style, content ) {
10986 return Roo.apply({},{
10988 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
10990 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
10993 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
11004 style : 'width:100%',
11011 cls : 'fc-header-left',
11013 fc_button('prev', 'left', 'arrow', '‹' ),
11014 fc_button('next', 'right', 'arrow', '›' ),
11015 { tag: 'span', cls: 'fc-header-space' },
11016 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
11024 cls : 'fc-header-center',
11028 cls: 'fc-header-title',
11031 html : 'month / year'
11039 cls : 'fc-header-right',
11041 /* fc_button('month', 'left', '', 'month' ),
11042 fc_button('week', '', '', 'week' ),
11043 fc_button('day', 'right', '', 'day' )
11055 header = this.header;
11058 var cal_heads = function() {
11060 // fixme - handle this.
11062 for (var i =0; i < Date.dayNames.length; i++) {
11063 var d = Date.dayNames[i];
11066 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
11067 html : d.substring(0,3)
11071 ret[0].cls += ' fc-first';
11072 ret[6].cls += ' fc-last';
11075 var cal_cell = function(n) {
11078 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
11083 cls: 'fc-day-number',
11087 cls: 'fc-day-content',
11091 style: 'position: relative;' // height: 17px;
11103 var cal_rows = function() {
11106 for (var r = 0; r < 6; r++) {
11113 for (var i =0; i < Date.dayNames.length; i++) {
11114 var d = Date.dayNames[i];
11115 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
11118 row.cn[0].cls+=' fc-first';
11119 row.cn[0].cn[0].style = 'min-height:90px';
11120 row.cn[6].cls+=' fc-last';
11124 ret[0].cls += ' fc-first';
11125 ret[4].cls += ' fc-prev-last';
11126 ret[5].cls += ' fc-last';
11133 cls: 'fc-border-separate',
11134 style : 'width:100%',
11142 cls : 'fc-first fc-last',
11160 cls : 'fc-content',
11161 style : "position: relative;",
11164 cls : 'fc-view fc-view-month fc-grid',
11165 style : 'position: relative',
11166 unselectable : 'on',
11169 cls : 'fc-event-container',
11170 style : 'position:absolute;z-index:8;top:0;left:0;'
11188 initEvents : function()
11191 throw "can not find store for calendar";
11197 style: "text-align:center",
11201 style: "background-color:white;width:50%;margin:250 auto",
11205 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
11216 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
11218 var size = this.el.select('.fc-content', true).first().getSize();
11219 this.maskEl.setSize(size.width, size.height);
11220 this.maskEl.enableDisplayMode("block");
11221 if(!this.loadMask){
11222 this.maskEl.hide();
11225 this.store = Roo.factory(this.store, Roo.data);
11226 this.store.on('load', this.onLoad, this);
11227 this.store.on('beforeload', this.onBeforeLoad, this);
11231 this.cells = this.el.select('.fc-day',true);
11232 //Roo.log(this.cells);
11233 this.textNodes = this.el.query('.fc-day-number');
11234 this.cells.addClassOnOver('fc-state-hover');
11236 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
11237 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
11238 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
11239 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
11241 this.on('monthchange', this.onMonthChange, this);
11243 this.update(new Date().clearTime());
11246 resize : function() {
11247 var sz = this.el.getSize();
11249 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
11250 this.el.select('.fc-day-content div',true).setHeight(34);
11255 showPrevMonth : function(e){
11256 this.update(this.activeDate.add("mo", -1));
11258 showToday : function(e){
11259 this.update(new Date().clearTime());
11262 showNextMonth : function(e){
11263 this.update(this.activeDate.add("mo", 1));
11267 showPrevYear : function(){
11268 this.update(this.activeDate.add("y", -1));
11272 showNextYear : function(){
11273 this.update(this.activeDate.add("y", 1));
11278 update : function(date)
11280 var vd = this.activeDate;
11281 this.activeDate = date;
11282 // if(vd && this.el){
11283 // var t = date.getTime();
11284 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
11285 // Roo.log('using add remove');
11287 // this.fireEvent('monthchange', this, date);
11289 // this.cells.removeClass("fc-state-highlight");
11290 // this.cells.each(function(c){
11291 // if(c.dateValue == t){
11292 // c.addClass("fc-state-highlight");
11293 // setTimeout(function(){
11294 // try{c.dom.firstChild.focus();}catch(e){}
11304 var days = date.getDaysInMonth();
11306 var firstOfMonth = date.getFirstDateOfMonth();
11307 var startingPos = firstOfMonth.getDay()-this.startDay;
11309 if(startingPos < this.startDay){
11313 var pm = date.add(Date.MONTH, -1);
11314 var prevStart = pm.getDaysInMonth()-startingPos;
11316 this.cells = this.el.select('.fc-day',true);
11317 this.textNodes = this.el.query('.fc-day-number');
11318 this.cells.addClassOnOver('fc-state-hover');
11320 var cells = this.cells.elements;
11321 var textEls = this.textNodes;
11323 Roo.each(cells, function(cell){
11324 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
11327 days += startingPos;
11329 // convert everything to numbers so it's fast
11330 var day = 86400000;
11331 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
11334 //Roo.log(prevStart);
11336 var today = new Date().clearTime().getTime();
11337 var sel = date.clearTime().getTime();
11338 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
11339 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
11340 var ddMatch = this.disabledDatesRE;
11341 var ddText = this.disabledDatesText;
11342 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
11343 var ddaysText = this.disabledDaysText;
11344 var format = this.format;
11346 var setCellClass = function(cal, cell){
11350 //Roo.log('set Cell Class');
11352 var t = d.getTime();
11356 cell.dateValue = t;
11358 cell.className += " fc-today";
11359 cell.className += " fc-state-highlight";
11360 cell.title = cal.todayText;
11363 // disable highlight in other month..
11364 //cell.className += " fc-state-highlight";
11369 cell.className = " fc-state-disabled";
11370 cell.title = cal.minText;
11374 cell.className = " fc-state-disabled";
11375 cell.title = cal.maxText;
11379 if(ddays.indexOf(d.getDay()) != -1){
11380 cell.title = ddaysText;
11381 cell.className = " fc-state-disabled";
11384 if(ddMatch && format){
11385 var fvalue = d.dateFormat(format);
11386 if(ddMatch.test(fvalue)){
11387 cell.title = ddText.replace("%0", fvalue);
11388 cell.className = " fc-state-disabled";
11392 if (!cell.initialClassName) {
11393 cell.initialClassName = cell.dom.className;
11396 cell.dom.className = cell.initialClassName + ' ' + cell.className;
11401 for(; i < startingPos; i++) {
11402 textEls[i].innerHTML = (++prevStart);
11403 d.setDate(d.getDate()+1);
11405 cells[i].className = "fc-past fc-other-month";
11406 setCellClass(this, cells[i]);
11411 for(; i < days; i++){
11412 intDay = i - startingPos + 1;
11413 textEls[i].innerHTML = (intDay);
11414 d.setDate(d.getDate()+1);
11416 cells[i].className = ''; // "x-date-active";
11417 setCellClass(this, cells[i]);
11421 for(; i < 42; i++) {
11422 textEls[i].innerHTML = (++extraDays);
11423 d.setDate(d.getDate()+1);
11425 cells[i].className = "fc-future fc-other-month";
11426 setCellClass(this, cells[i]);
11429 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
11431 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
11433 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
11434 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
11436 if(totalRows != 6){
11437 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
11438 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
11441 this.fireEvent('monthchange', this, date);
11445 if(!this.internalRender){
11446 var main = this.el.dom.firstChild;
11447 var w = main.offsetWidth;
11448 this.el.setWidth(w + this.el.getBorderWidth("lr"));
11449 Roo.fly(main).setWidth(w);
11450 this.internalRender = true;
11451 // opera does not respect the auto grow header center column
11452 // then, after it gets a width opera refuses to recalculate
11453 // without a second pass
11454 if(Roo.isOpera && !this.secondPass){
11455 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
11456 this.secondPass = true;
11457 this.update.defer(10, this, [date]);
11464 findCell : function(dt) {
11465 dt = dt.clearTime().getTime();
11467 this.cells.each(function(c){
11468 //Roo.log("check " +c.dateValue + '?=' + dt);
11469 if(c.dateValue == dt){
11479 findCells : function(ev) {
11480 var s = ev.start.clone().clearTime().getTime();
11482 var e= ev.end.clone().clearTime().getTime();
11485 this.cells.each(function(c){
11486 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
11488 if(c.dateValue > e){
11491 if(c.dateValue < s){
11500 // findBestRow: function(cells)
11504 // for (var i =0 ; i < cells.length;i++) {
11505 // ret = Math.max(cells[i].rows || 0,ret);
11512 addItem : function(ev)
11514 // look for vertical location slot in
11515 var cells = this.findCells(ev);
11517 // ev.row = this.findBestRow(cells);
11519 // work out the location.
11523 for(var i =0; i < cells.length; i++) {
11525 cells[i].row = cells[0].row;
11528 cells[i].row = cells[i].row + 1;
11538 if (crow.start.getY() == cells[i].getY()) {
11540 crow.end = cells[i];
11557 cells[0].events.push(ev);
11559 // if((typeof(cells[0].events) == 'undefined')){
11560 // cells[0].events = [];
11563 // cells[0].events.push(ev);
11564 // ev.rendered = false;
11565 // for (var i = 0; i < cells.length;i++) {
11566 // cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
11570 this.calevents.push(ev);
11573 clearEvents: function() {
11575 if(!this.calevents){
11579 Roo.each(this.cells.elements, function(c){
11585 Roo.each(this.calevents, function(e) {
11586 Roo.each(e.els, function(el) {
11587 el.un('mouseenter' ,this.onEventEnter, this);
11588 el.un('mouseleave' ,this.onEventLeave, this);
11593 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
11599 renderEvents: function()
11601 // for (var e = 0; e < this.calevents.length; e++) {
11603 // var ev = this.calevents[e];
11604 // var cells = ev.cells;
11605 // var rows = ev.rows;
11607 // for (var j = 0; j < cells.length; j++){
11609 // if(!cells[j].more.length){
11612 // if(cells[j].row > 3){
11613 // cells[j].more.push(ev);
11617 // cells[j].events.push(ev);
11621 // for (var i = 0; i < rows.length; i++){
11622 // // how many rows should it span..
11625 // cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
11626 // style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
11628 // unselectable : "on",
11631 // cls: 'fc-event-inner',
11635 //// cls: 'fc-event-time',
11636 //// html : cells.length > 1 ? '' : ev.time
11640 // cls: 'fc-event-title',
11641 // html : String.format('{0}', ev.title)
11648 // cls: 'ui-resizable-handle ui-resizable-e',
11649 // html : '  '
11656 // cfg.cls += ' fc-event-start';
11658 // if ((i+1) == rows.length) {
11659 // cfg.cls += ' fc-event-end';
11662 // var ctr = this.el.select('.fc-event-container',true).first();
11663 // var cg = ctr.createChild(cfg);
11665 // var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
11666 // var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
11668 // cg.setXY([sbox.x +2, sbox.y +(e * 20)]);
11669 // cg.setWidth(ebox.right - sbox.x -2);
11671 // cg.on('mouseenter' ,this.onEventEnter, this, ev);
11672 // cg.on('mouseleave' ,this.onEventLeave, this, ev);
11673 // cg.on('click', this.onEventClick, this, ev);
11675 // ev.els.push(cg);
11683 this.cells.each(function(c) {
11692 if(c.row != c.events.length){
11693 r = 4 - (4 - (c.row - c.events.length));
11696 c.events = ev.slice(0, r);
11697 c.more = ev.slice(r);
11699 if(c.more.length && c.more.length == 1){
11700 c.events.push(c.more.pop());
11703 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
11707 // for (var e = 0; e < this.calevents.length; e++) {
11709 // var ev = this.calevents[e];
11710 // var cells = ev.cells;
11711 // var rows = ev.rows;
11713 // for(var i = 0; i < cells.length; i++){
11715 // var cbox = this.cells.item(this.cells.indexOf(cells[i]));
11717 // if(cells.length < 2 && cbox.rows.length > 3){
11718 // cbox.more.push(ev);
11722 // cbox.rows.push(ev);
11726 this.cells.each(function(c) {
11728 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
11731 for (var e = 0; e < c.events.length; e++){
11732 var ev = c.events[e];
11733 var rows = ev.rows;
11735 for(var i = 0; i < rows.length; i++) {
11737 // how many rows should it span..
11740 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
11741 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
11743 unselectable : "on",
11746 cls: 'fc-event-inner',
11750 // cls: 'fc-event-time',
11751 // html : cells.length > 1 ? '' : ev.time
11755 cls: 'fc-event-title',
11756 html : String.format('{0}', ev.title)
11763 cls: 'ui-resizable-handle ui-resizable-e',
11764 html : '  '
11771 cfg.cls += ' fc-event-start';
11773 if ((i+1) == rows.length) {
11774 cfg.cls += ' fc-event-end';
11777 var ctr = _this.el.select('.fc-event-container',true).first();
11778 var cg = ctr.createChild(cfg);
11780 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
11781 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
11783 var r = (c.more.length) ? 1 : 0;
11784 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
11785 cg.setWidth(ebox.right - sbox.x -2);
11787 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
11788 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
11789 cg.on('click', _this.onEventClick, _this, ev);
11800 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
11801 style : 'position: absolute',
11802 unselectable : "on",
11805 cls: 'fc-event-inner',
11809 cls: 'fc-event-title',
11817 cls: 'ui-resizable-handle ui-resizable-e',
11818 html : '  '
11824 var ctr = _this.el.select('.fc-event-container',true).first();
11825 var cg = ctr.createChild(cfg);
11827 var sbox = c.select('.fc-day-content',true).first().getBox();
11828 var ebox = c.select('.fc-day-content',true).first().getBox();
11830 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
11831 cg.setWidth(ebox.right - sbox.x -2);
11833 cg.on('click', _this.onMoreEventClick, _this, c.more);
11843 onEventEnter: function (e, el,event,d) {
11844 this.fireEvent('evententer', this, el, event);
11847 onEventLeave: function (e, el,event,d) {
11848 this.fireEvent('eventleave', this, el, event);
11851 onEventClick: function (e, el,event,d) {
11852 this.fireEvent('eventclick', this, el, event);
11855 onMonthChange: function () {
11859 onMoreEventClick: function(e, el, more)
11863 this.calpopover.placement = 'right';
11864 this.calpopover.setTitle('More');
11866 this.calpopover.setContent('');
11868 var ctr = this.calpopover.el.select('.popover-content', true).first();
11870 Roo.each(more, function(m){
11872 cls : 'fc-event-hori fc-event-draggable',
11875 var cg = ctr.createChild(cfg);
11877 cg.on('click', _this.onEventClick, _this, m);
11880 this.calpopover.show(el);
11885 onLoad: function ()
11887 this.calevents = [];
11890 if(this.store.getCount() > 0){
11891 this.store.data.each(function(d){
11894 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
11895 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
11896 time : d.data.start_time,
11897 title : d.data.title,
11898 description : d.data.description,
11899 venue : d.data.venue
11904 this.renderEvents();
11906 if(this.calevents.length && this.loadMask){
11907 this.maskEl.hide();
11911 onBeforeLoad: function()
11913 this.clearEvents();
11915 this.maskEl.show();
11929 * @class Roo.bootstrap.Popover
11930 * @extends Roo.bootstrap.Component
11931 * Bootstrap Popover class
11932 * @cfg {String} html contents of the popover (or false to use children..)
11933 * @cfg {String} title of popover (or false to hide)
11934 * @cfg {String} placement how it is placed
11935 * @cfg {String} trigger click || hover (or false to trigger manually)
11936 * @cfg {String} over what (parent or false to trigger manually.)
11939 * Create a new Popover
11940 * @param {Object} config The config object
11943 Roo.bootstrap.Popover = function(config){
11944 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
11947 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
11949 title: 'Fill in a title',
11952 placement : 'right',
11953 trigger : 'hover', // hover
11957 can_build_overlaid : false,
11959 getChildContainer : function()
11961 return this.el.select('.popover-content',true).first();
11964 getAutoCreate : function(){
11965 Roo.log('make popover?');
11967 cls : 'popover roo-dynamic',
11968 style: 'display:block',
11974 cls : 'popover-inner',
11978 cls: 'popover-title',
11982 cls : 'popover-content',
11993 setTitle: function(str)
11995 this.el.select('.popover-title',true).first().dom.innerHTML = str;
11997 setContent: function(str)
11999 this.el.select('.popover-content',true).first().dom.innerHTML = str;
12001 // as it get's added to the bottom of the page.
12002 onRender : function(ct, position)
12004 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
12006 var cfg = Roo.apply({}, this.getAutoCreate());
12010 cfg.cls += ' ' + this.cls;
12013 cfg.style = this.style;
12015 Roo.log("adding to ")
12016 this.el = Roo.get(document.body).createChild(cfg, position);
12022 initEvents : function()
12024 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
12025 this.el.enableDisplayMode('block');
12027 if (this.over === false) {
12030 if (this.triggers === false) {
12033 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
12034 var triggers = this.trigger ? this.trigger.split(' ') : [];
12035 Roo.each(triggers, function(trigger) {
12037 if (trigger == 'click') {
12038 on_el.on('click', this.toggle, this);
12039 } else if (trigger != 'manual') {
12040 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
12041 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
12043 on_el.on(eventIn ,this.enter, this);
12044 on_el.on(eventOut, this.leave, this);
12055 toggle : function () {
12056 this.hoverState == 'in' ? this.leave() : this.enter();
12059 enter : function () {
12062 clearTimeout(this.timeout);
12064 this.hoverState = 'in'
12066 if (!this.delay || !this.delay.show) {
12071 this.timeout = setTimeout(function () {
12072 if (_t.hoverState == 'in') {
12075 }, this.delay.show)
12077 leave : function() {
12078 clearTimeout(this.timeout);
12080 this.hoverState = 'out'
12082 if (!this.delay || !this.delay.hide) {
12087 this.timeout = setTimeout(function () {
12088 if (_t.hoverState == 'out') {
12091 }, this.delay.hide)
12094 show : function (on_el)
12097 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
12100 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
12101 if (this.html !== false) {
12102 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
12104 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
12105 if (!this.title.length) {
12106 this.el.select('.popover-title',true).hide();
12109 var placement = typeof this.placement == 'function' ?
12110 this.placement.call(this, this.el, on_el) :
12113 var autoToken = /\s?auto?\s?/i;
12114 var autoPlace = autoToken.test(placement);
12116 placement = placement.replace(autoToken, '') || 'top';
12120 //this.el.setXY([0,0]);
12122 this.el.dom.style.display='block';
12123 this.el.addClass(placement);
12125 //this.el.appendTo(on_el);
12127 var p = this.getPosition();
12128 var box = this.el.getBox();
12133 var align = Roo.bootstrap.Popover.alignment[placement]
12134 this.el.alignTo(on_el, align[0],align[1]);
12135 //var arrow = this.el.select('.arrow',true).first();
12136 //arrow.set(align[2],
12138 this.el.addClass('in');
12139 this.hoverState = null;
12141 if (this.el.hasClass('fade')) {
12148 this.el.setXY([0,0]);
12149 this.el.removeClass('in');
12156 Roo.bootstrap.Popover.alignment = {
12157 'left' : ['r-l', [-10,0], 'right'],
12158 'right' : ['l-r', [10,0], 'left'],
12159 'bottom' : ['t-b', [0,10], 'top'],
12160 'top' : [ 'b-t', [0,-10], 'bottom']
12171 * @class Roo.bootstrap.Progress
12172 * @extends Roo.bootstrap.Component
12173 * Bootstrap Progress class
12174 * @cfg {Boolean} striped striped of the progress bar
12175 * @cfg {Boolean} active animated of the progress bar
12179 * Create a new Progress
12180 * @param {Object} config The config object
12183 Roo.bootstrap.Progress = function(config){
12184 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
12187 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
12192 getAutoCreate : function(){
12200 cfg.cls += ' progress-striped';
12204 cfg.cls += ' active';
12223 * @class Roo.bootstrap.ProgressBar
12224 * @extends Roo.bootstrap.Component
12225 * Bootstrap ProgressBar class
12226 * @cfg {Number} aria_valuenow aria-value now
12227 * @cfg {Number} aria_valuemin aria-value min
12228 * @cfg {Number} aria_valuemax aria-value max
12229 * @cfg {String} label label for the progress bar
12230 * @cfg {String} panel (success | info | warning | danger )
12231 * @cfg {String} role role of the progress bar
12232 * @cfg {String} sr_only text
12236 * Create a new ProgressBar
12237 * @param {Object} config The config object
12240 Roo.bootstrap.ProgressBar = function(config){
12241 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
12244 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
12248 aria_valuemax : 100,
12254 getAutoCreate : function()
12259 cls: 'progress-bar',
12260 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
12272 cfg.role = this.role;
12275 if(this.aria_valuenow){
12276 cfg['aria-valuenow'] = this.aria_valuenow;
12279 if(this.aria_valuemin){
12280 cfg['aria-valuemin'] = this.aria_valuemin;
12283 if(this.aria_valuemax){
12284 cfg['aria-valuemax'] = this.aria_valuemax;
12287 if(this.label && !this.sr_only){
12288 cfg.html = this.label;
12292 cfg.cls += ' progress-bar-' + this.panel;
12298 update : function(aria_valuenow)
12300 this.aria_valuenow = aria_valuenow;
12302 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
12317 * @class Roo.bootstrap.TabPanel
12318 * @extends Roo.bootstrap.Component
12319 * Bootstrap TabPanel class
12320 * @cfg {Boolean} active panel active
12321 * @cfg {String} html panel content
12322 * @cfg {String} tabId tab relate id
12323 * @cfg {String} navId The navbar which triggers show hide
12327 * Create a new TabPanel
12328 * @param {Object} config The config object
12331 Roo.bootstrap.TabPanel = function(config){
12332 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
12336 * Fires when the active status changes
12337 * @param {Roo.bootstrap.TabPanel} this
12338 * @param {Boolean} state the new state
12345 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
12352 getAutoCreate : function(){
12356 html: this.html || ''
12360 cfg.cls += ' active';
12364 cfg.tabId = this.tabId;
12369 onRender : function(ct, position)
12371 // Roo.log("Call onRender: " + this.xtype);
12373 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
12375 if (this.navId && this.tabId) {
12376 var item = Roo.bootstrap.NavGroup.get(this.navId).getNavItem(this.tabId);
12378 Roo.log("could not find navID:" + this.navId + ", tabId: " + this.tabId);
12380 item.on('changed', function(item, state) {
12381 this.setActive(state);
12387 setActive: function(state)
12389 Roo.log("panel - set active " + this.tabId + "=" + state);
12391 this.active = state;
12393 this.el.removeClass('active');
12395 } else if (!this.el.hasClass('active')) {
12396 this.el.addClass('active');
12398 this.fireEvent('changed', this, state);
12415 * @class Roo.bootstrap.DateField
12416 * @extends Roo.bootstrap.Input
12417 * Bootstrap DateField class
12418 * @cfg {Number} weekStart default 0
12419 * @cfg {Number} weekStart default 0
12420 * @cfg {Number} viewMode default empty, (months|years)
12421 * @cfg {Number} minViewMode default empty, (months|years)
12422 * @cfg {Number} startDate default -Infinity
12423 * @cfg {Number} endDate default Infinity
12424 * @cfg {Boolean} todayHighlight default false
12425 * @cfg {Boolean} todayBtn default false
12426 * @cfg {Boolean} calendarWeeks default false
12427 * @cfg {Object} daysOfWeekDisabled default empty
12429 * @cfg {Boolean} keyboardNavigation default true
12430 * @cfg {String} language default en
12433 * Create a new DateField
12434 * @param {Object} config The config object
12437 Roo.bootstrap.DateField = function(config){
12438 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
12442 * Fires when this field show.
12443 * @param {Roo.bootstrap.DateField} this
12444 * @param {Mixed} date The date value
12449 * Fires when this field hide.
12450 * @param {Roo.bootstrap.DateField} this
12451 * @param {Mixed} date The date value
12456 * Fires when select a date.
12457 * @param {Roo.bootstrap.DateField} this
12458 * @param {Mixed} date The date value
12464 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
12467 * @cfg {String} format
12468 * The default date format string which can be overriden for localization support. The format must be
12469 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
12473 * @cfg {String} altFormats
12474 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
12475 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
12477 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
12485 todayHighlight : false,
12491 keyboardNavigation: true,
12493 calendarWeeks: false,
12495 startDate: -Infinity,
12499 daysOfWeekDisabled: [],
12503 UTCDate: function()
12505 return new Date(Date.UTC.apply(Date, arguments));
12508 UTCToday: function()
12510 var today = new Date();
12511 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
12514 getDate: function() {
12515 var d = this.getUTCDate();
12516 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
12519 getUTCDate: function() {
12523 setDate: function(d) {
12524 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
12527 setUTCDate: function(d) {
12529 this.setValue(this.formatDate(this.date));
12532 onRender: function(ct, position)
12535 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
12537 this.language = this.language || 'en';
12538 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
12539 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
12541 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
12542 this.format = this.format || 'm/d/y';
12543 this.isInline = false;
12544 this.isInput = true;
12545 this.component = this.el.select('.add-on', true).first() || false;
12546 this.component = (this.component && this.component.length === 0) ? false : this.component;
12547 this.hasInput = this.component && this.inputEL().length;
12549 if (typeof(this.minViewMode === 'string')) {
12550 switch (this.minViewMode) {
12552 this.minViewMode = 1;
12555 this.minViewMode = 2;
12558 this.minViewMode = 0;
12563 if (typeof(this.viewMode === 'string')) {
12564 switch (this.viewMode) {
12577 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
12579 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12581 this.picker().on('mousedown', this.onMousedown, this);
12582 this.picker().on('click', this.onClick, this);
12584 this.picker().addClass('datepicker-dropdown');
12586 this.startViewMode = this.viewMode;
12589 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
12590 if(!this.calendarWeeks){
12595 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
12596 v.attr('colspan', function(i, val){
12597 return parseInt(val) + 1;
12602 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
12604 this.setStartDate(this.startDate);
12605 this.setEndDate(this.endDate);
12607 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
12614 if(this.isInline) {
12619 picker : function()
12621 return this.el.select('.datepicker', true).first();
12624 fillDow: function()
12626 var dowCnt = this.weekStart;
12635 if(this.calendarWeeks){
12643 while (dowCnt < this.weekStart + 7) {
12647 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
12651 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
12654 fillMonths: function()
12657 var months = this.picker().select('>.datepicker-months td', true).first();
12659 months.dom.innerHTML = '';
12665 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
12668 months.createChild(month);
12673 update: function(){
12675 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
12677 if (this.date < this.startDate) {
12678 this.viewDate = new Date(this.startDate);
12679 } else if (this.date > this.endDate) {
12680 this.viewDate = new Date(this.endDate);
12682 this.viewDate = new Date(this.date);
12689 var d = new Date(this.viewDate),
12690 year = d.getUTCFullYear(),
12691 month = d.getUTCMonth(),
12692 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
12693 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
12694 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
12695 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
12696 currentDate = this.date && this.date.valueOf(),
12697 today = this.UTCToday();
12699 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
12701 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
12703 // this.picker.select('>tfoot th.today').
12704 // .text(dates[this.language].today)
12705 // .toggle(this.todayBtn !== false);
12707 this.updateNavArrows();
12710 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
12712 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
12714 prevMonth.setUTCDate(day);
12716 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
12718 var nextMonth = new Date(prevMonth);
12720 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
12722 nextMonth = nextMonth.valueOf();
12724 var fillMonths = false;
12726 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
12728 while(prevMonth.valueOf() < nextMonth) {
12731 if (prevMonth.getUTCDay() === this.weekStart) {
12733 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
12741 if(this.calendarWeeks){
12742 // ISO 8601: First week contains first thursday.
12743 // ISO also states week starts on Monday, but we can be more abstract here.
12745 // Start of current week: based on weekstart/current date
12746 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
12747 // Thursday of this week
12748 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
12749 // First Thursday of year, year from thursday
12750 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
12751 // Calendar week: ms between thursdays, div ms per day, div 7 days
12752 calWeek = (th - yth) / 864e5 / 7 + 1;
12754 fillMonths.cn.push({
12762 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
12764 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
12767 if (this.todayHighlight &&
12768 prevMonth.getUTCFullYear() == today.getFullYear() &&
12769 prevMonth.getUTCMonth() == today.getMonth() &&
12770 prevMonth.getUTCDate() == today.getDate()) {
12771 clsName += ' today';
12774 if (currentDate && prevMonth.valueOf() === currentDate) {
12775 clsName += ' active';
12778 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
12779 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
12780 clsName += ' disabled';
12783 fillMonths.cn.push({
12785 cls: 'day ' + clsName,
12786 html: prevMonth.getDate()
12789 prevMonth.setDate(prevMonth.getDate()+1);
12792 var currentYear = this.date && this.date.getUTCFullYear();
12793 var currentMonth = this.date && this.date.getUTCMonth();
12795 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
12797 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
12798 v.removeClass('active');
12800 if(currentYear === year && k === currentMonth){
12801 v.addClass('active');
12804 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
12805 v.addClass('disabled');
12811 year = parseInt(year/10, 10) * 10;
12813 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
12815 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
12818 for (var i = -1; i < 11; i++) {
12819 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
12821 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
12829 showMode: function(dir) {
12831 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
12833 Roo.each(this.picker().select('>div',true).elements, function(v){
12834 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12837 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
12842 if(this.isInline) return;
12844 this.picker().removeClass(['bottom', 'top']);
12846 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
12848 * place to the top of element!
12852 this.picker().addClass('top');
12853 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12858 this.picker().addClass('bottom');
12860 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12863 parseDate : function(value){
12864 if(!value || value instanceof Date){
12867 var v = Date.parseDate(value, this.format);
12868 if (!v && this.useIso) {
12869 v = Date.parseDate(value, 'Y-m-d');
12871 if(!v && this.altFormats){
12872 if(!this.altFormatsArray){
12873 this.altFormatsArray = this.altFormats.split("|");
12875 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
12876 v = Date.parseDate(value, this.altFormatsArray[i]);
12882 formatDate : function(date, fmt){
12883 return (!date || !(date instanceof Date)) ?
12884 date : date.dateFormat(fmt || this.format);
12887 onFocus : function()
12889 Roo.bootstrap.DateField.superclass.onFocus.call(this);
12893 onBlur : function()
12895 Roo.bootstrap.DateField.superclass.onBlur.call(this);
12901 this.picker().show();
12905 this.fireEvent('show', this, this.date);
12910 if(this.isInline) return;
12911 this.picker().hide();
12912 this.viewMode = this.startViewMode;
12915 this.fireEvent('hide', this, this.date);
12919 onMousedown: function(e){
12920 e.stopPropagation();
12921 e.preventDefault();
12924 keyup: function(e){
12925 Roo.bootstrap.DateField.superclass.keyup.call(this);
12930 setValue: function(v){
12931 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
12933 this.fireEvent('select', this, this.date);
12937 fireKey: function(e){
12938 if (!this.picker().isVisible()){
12939 if (e.keyCode == 27) // allow escape to hide and re-show picker
12943 var dateChanged = false,
12945 newDate, newViewDate;
12949 e.preventDefault();
12953 if (!this.keyboardNavigation) break;
12954 dir = e.keyCode == 37 ? -1 : 1;
12957 newDate = this.moveYear(this.date, dir);
12958 newViewDate = this.moveYear(this.viewDate, dir);
12959 } else if (e.shiftKey){
12960 newDate = this.moveMonth(this.date, dir);
12961 newViewDate = this.moveMonth(this.viewDate, dir);
12963 newDate = new Date(this.date);
12964 newDate.setUTCDate(this.date.getUTCDate() + dir);
12965 newViewDate = new Date(this.viewDate);
12966 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
12968 if (this.dateWithinRange(newDate)){
12969 this.date = newDate;
12970 this.viewDate = newViewDate;
12971 this.setValue(this.formatDate(this.date));
12973 e.preventDefault();
12974 dateChanged = true;
12979 if (!this.keyboardNavigation) break;
12980 dir = e.keyCode == 38 ? -1 : 1;
12982 newDate = this.moveYear(this.date, dir);
12983 newViewDate = this.moveYear(this.viewDate, dir);
12984 } else if (e.shiftKey){
12985 newDate = this.moveMonth(this.date, dir);
12986 newViewDate = this.moveMonth(this.viewDate, dir);
12988 newDate = new Date(this.date);
12989 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
12990 newViewDate = new Date(this.viewDate);
12991 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
12993 if (this.dateWithinRange(newDate)){
12994 this.date = newDate;
12995 this.viewDate = newViewDate;
12996 this.setValue(this.formatDate(this.date));
12998 e.preventDefault();
12999 dateChanged = true;
13003 this.setValue(this.formatDate(this.date));
13005 e.preventDefault();
13008 this.setValue(this.formatDate(this.date));
13015 onClick: function(e) {
13016 e.stopPropagation();
13017 e.preventDefault();
13019 var target = e.getTarget();
13021 if(target.nodeName.toLowerCase() === 'i'){
13022 target = Roo.get(target).dom.parentNode;
13025 var nodeName = target.nodeName;
13026 var className = target.className;
13027 var html = target.innerHTML;
13029 switch(nodeName.toLowerCase()) {
13031 switch(className) {
13037 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
13038 switch(this.viewMode){
13040 this.viewDate = this.moveMonth(this.viewDate, dir);
13044 this.viewDate = this.moveYear(this.viewDate, dir);
13050 var date = new Date();
13051 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
13053 this.setValue(this.formatDate(this.date));
13059 if (className.indexOf('disabled') === -1) {
13060 this.viewDate.setUTCDate(1);
13061 if (className.indexOf('month') !== -1) {
13062 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
13064 var year = parseInt(html, 10) || 0;
13065 this.viewDate.setUTCFullYear(year);
13074 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
13075 var day = parseInt(html, 10) || 1;
13076 var year = this.viewDate.getUTCFullYear(),
13077 month = this.viewDate.getUTCMonth();
13079 if (className.indexOf('old') !== -1) {
13086 } else if (className.indexOf('new') !== -1) {
13094 this.date = this.UTCDate(year, month, day,0,0,0,0);
13095 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
13097 this.setValue(this.formatDate(this.date));
13104 setStartDate: function(startDate){
13105 this.startDate = startDate || -Infinity;
13106 if (this.startDate !== -Infinity) {
13107 this.startDate = this.parseDate(this.startDate);
13110 this.updateNavArrows();
13113 setEndDate: function(endDate){
13114 this.endDate = endDate || Infinity;
13115 if (this.endDate !== Infinity) {
13116 this.endDate = this.parseDate(this.endDate);
13119 this.updateNavArrows();
13122 setDaysOfWeekDisabled: function(daysOfWeekDisabled){
13123 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
13124 if (typeof(this.daysOfWeekDisabled) !== 'object') {
13125 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
13127 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
13128 return parseInt(d, 10);
13131 this.updateNavArrows();
13134 updateNavArrows: function() {
13135 var d = new Date(this.viewDate),
13136 year = d.getUTCFullYear(),
13137 month = d.getUTCMonth();
13139 Roo.each(this.picker().select('.prev', true).elements, function(v){
13141 switch (this.viewMode) {
13144 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
13150 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
13157 Roo.each(this.picker().select('.next', true).elements, function(v){
13159 switch (this.viewMode) {
13162 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
13168 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
13176 moveMonth: function(date, dir){
13177 if (!dir) return date;
13178 var new_date = new Date(date.valueOf()),
13179 day = new_date.getUTCDate(),
13180 month = new_date.getUTCMonth(),
13181 mag = Math.abs(dir),
13183 dir = dir > 0 ? 1 : -1;
13186 // If going back one month, make sure month is not current month
13187 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
13189 return new_date.getUTCMonth() == month;
13191 // If going forward one month, make sure month is as expected
13192 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
13194 return new_date.getUTCMonth() != new_month;
13196 new_month = month + dir;
13197 new_date.setUTCMonth(new_month);
13198 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
13199 if (new_month < 0 || new_month > 11)
13200 new_month = (new_month + 12) % 12;
13202 // For magnitudes >1, move one month at a time...
13203 for (var i=0; i<mag; i++)
13204 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
13205 new_date = this.moveMonth(new_date, dir);
13206 // ...then reset the day, keeping it in the new month
13207 new_month = new_date.getUTCMonth();
13208 new_date.setUTCDate(day);
13210 return new_month != new_date.getUTCMonth();
13213 // Common date-resetting loop -- if date is beyond end of month, make it
13216 new_date.setUTCDate(--day);
13217 new_date.setUTCMonth(new_month);
13222 moveYear: function(date, dir){
13223 return this.moveMonth(date, dir*12);
13226 dateWithinRange: function(date){
13227 return date >= this.startDate && date <= this.endDate;
13231 remove: function() {
13232 this.picker().remove();
13237 Roo.apply(Roo.bootstrap.DateField, {
13248 html: '<i class="icon-arrow-left"/>'
13258 html: '<i class="icon-arrow-right"/>'
13300 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
13301 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
13302 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
13303 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
13304 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
13317 navFnc: 'FullYear',
13322 navFnc: 'FullYear',
13327 Roo.apply(Roo.bootstrap.DateField, {
13331 cls: 'datepicker dropdown-menu',
13335 cls: 'datepicker-days',
13339 cls: 'table-condensed',
13341 Roo.bootstrap.DateField.head,
13345 Roo.bootstrap.DateField.footer
13352 cls: 'datepicker-months',
13356 cls: 'table-condensed',
13358 Roo.bootstrap.DateField.head,
13359 Roo.bootstrap.DateField.content,
13360 Roo.bootstrap.DateField.footer
13367 cls: 'datepicker-years',
13371 cls: 'table-condensed',
13373 Roo.bootstrap.DateField.head,
13374 Roo.bootstrap.DateField.content,
13375 Roo.bootstrap.DateField.footer
13394 * @class Roo.bootstrap.TimeField
13395 * @extends Roo.bootstrap.Input
13396 * Bootstrap DateField class
13400 * Create a new TimeField
13401 * @param {Object} config The config object
13404 Roo.bootstrap.TimeField = function(config){
13405 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
13409 * Fires when this field show.
13410 * @param {Roo.bootstrap.DateField} this
13411 * @param {Mixed} date The date value
13416 * Fires when this field hide.
13417 * @param {Roo.bootstrap.DateField} this
13418 * @param {Mixed} date The date value
13423 * Fires when select a date.
13424 * @param {Roo.bootstrap.DateField} this
13425 * @param {Mixed} date The date value
13431 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
13434 * @cfg {String} format
13435 * The default time format string which can be overriden for localization support. The format must be
13436 * valid according to {@link Date#parseDate} (defaults to 'H:i').
13440 onRender: function(ct, position)
13443 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
13445 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
13447 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13449 this.pop = this.picker().select('>.datepicker-time',true).first();
13450 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
13452 this.picker().on('mousedown', this.onMousedown, this);
13453 this.picker().on('click', this.onClick, this);
13455 this.picker().addClass('datepicker-dropdown');
13460 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
13461 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
13462 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
13463 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
13464 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
13465 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
13469 fireKey: function(e){
13470 if (!this.picker().isVisible()){
13471 if (e.keyCode == 27) // allow escape to hide and re-show picker
13476 e.preventDefault();
13484 this.onTogglePeriod();
13487 this.onIncrementMinutes();
13490 this.onDecrementMinutes();
13499 onClick: function(e) {
13500 e.stopPropagation();
13501 e.preventDefault();
13504 picker : function()
13506 return this.el.select('.datepicker', true).first();
13509 fillTime: function()
13511 var time = this.pop.select('tbody', true).first();
13513 time.dom.innerHTML = '';
13528 cls: 'hours-up glyphicon glyphicon-chevron-up'
13548 cls: 'minutes-up glyphicon glyphicon-chevron-up'
13569 cls: 'timepicker-hour',
13584 cls: 'timepicker-minute',
13599 cls: 'btn btn-primary period',
13621 cls: 'hours-down glyphicon glyphicon-chevron-down'
13641 cls: 'minutes-down glyphicon glyphicon-chevron-down'
13659 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
13666 var hours = this.time.getHours();
13667 var minutes = this.time.getMinutes();
13680 hours = hours - 12;
13684 hours = '0' + hours;
13688 minutes = '0' + minutes;
13691 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
13692 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
13693 this.pop.select('button', true).first().dom.innerHTML = period;
13699 this.picker().removeClass(['bottom', 'top']);
13701 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
13703 * place to the top of element!
13707 this.picker().addClass('top');
13708 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13713 this.picker().addClass('bottom');
13715 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13718 onFocus : function()
13720 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
13724 onBlur : function()
13726 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
13732 this.picker().show();
13737 this.fireEvent('show', this, this.date);
13742 this.picker().hide();
13745 this.fireEvent('hide', this, this.date);
13748 setTime : function()
13751 this.setValue(this.time.format(this.format));
13753 this.fireEvent('select', this, this.date);
13758 onMousedown: function(e){
13759 e.stopPropagation();
13760 e.preventDefault();
13763 onIncrementHours: function()
13765 Roo.log('onIncrementHours');
13766 this.time = this.time.add(Date.HOUR, 1);
13771 onDecrementHours: function()
13773 Roo.log('onDecrementHours');
13774 this.time = this.time.add(Date.HOUR, -1);
13778 onIncrementMinutes: function()
13780 Roo.log('onIncrementMinutes');
13781 this.time = this.time.add(Date.MINUTE, 1);
13785 onDecrementMinutes: function()
13787 Roo.log('onDecrementMinutes');
13788 this.time = this.time.add(Date.MINUTE, -1);
13792 onTogglePeriod: function()
13794 Roo.log('onTogglePeriod');
13795 this.time = this.time.add(Date.HOUR, 12);
13802 Roo.apply(Roo.bootstrap.TimeField, {
13832 cls: 'btn btn-info ok',
13844 Roo.apply(Roo.bootstrap.TimeField, {
13848 cls: 'datepicker dropdown-menu',
13852 cls: 'datepicker-time',
13856 cls: 'table-condensed',
13858 Roo.bootstrap.TimeField.content,
13859 Roo.bootstrap.TimeField.footer
13878 * @class Roo.bootstrap.CheckBox
13879 * @extends Roo.bootstrap.Input
13880 * Bootstrap CheckBox class
13882 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
13883 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
13884 * @cfg {String} boxLabel The text that appears beside the checkbox
13885 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
13886 * @cfg {Boolean} checked initnal the element
13890 * Create a new CheckBox
13891 * @param {Object} config The config object
13894 Roo.bootstrap.CheckBox = function(config){
13895 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
13900 * Fires when the element is checked or unchecked.
13901 * @param {Roo.bootstrap.CheckBox} this This input
13902 * @param {Boolean} checked The new checked value
13908 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
13910 inputType: 'checkbox',
13917 getAutoCreate : function()
13919 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
13925 cfg.cls = 'form-group checkbox' //input-group
13933 type : this.inputType,
13934 value : (!this.checked) ? this.valueOff : this.inputValue,
13935 cls : 'roo-checkbox', //'form-box',
13936 placeholder : this.placeholder || ''
13940 if (this.weight) { // Validity check?
13941 cfg.cls += " checkbox-" + this.weight;
13944 if (this.disabled) {
13945 input.disabled=true;
13949 input.checked = this.checked;
13953 input.name = this.name;
13957 input.cls += ' input-' + this.size;
13961 ['xs','sm','md','lg'].map(function(size){
13962 if (settings[size]) {
13963 cfg.cls += ' col-' + size + '-' + settings[size];
13969 var inputblock = input;
13974 if (this.before || this.after) {
13977 cls : 'input-group',
13981 inputblock.cn.push({
13983 cls : 'input-group-addon',
13987 inputblock.cn.push(input);
13989 inputblock.cn.push({
13991 cls : 'input-group-addon',
13998 if (align ==='left' && this.fieldLabel.length) {
13999 Roo.log("left and has label");
14005 cls : 'control-label col-md-' + this.labelWidth,
14006 html : this.fieldLabel
14010 cls : "col-md-" + (12 - this.labelWidth),
14017 } else if ( this.fieldLabel.length) {
14022 tag: this.boxLabel ? 'span' : 'label',
14024 cls: 'control-label box-input-label',
14025 //cls : 'input-group-addon',
14026 html : this.fieldLabel
14036 Roo.log(" no label && no align");
14037 cfg.cn = [ inputblock ] ;
14046 html: this.boxLabel
14058 * return the real input element.
14060 inputEl: function ()
14062 return this.el.select('input.roo-checkbox',true).first();
14067 return this.el.select('label.control-label',true).first();
14070 initEvents : function()
14072 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
14074 this.inputEl().on('click', this.onClick, this);
14078 onClick : function()
14080 this.setChecked(!this.checked);
14083 setChecked : function(state,suppressEvent)
14085 this.checked = state;
14087 this.inputEl().dom.checked = state;
14089 if(suppressEvent !== true){
14090 this.fireEvent('check', this, state);
14093 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
14097 setValue : function(v,suppressEvent)
14099 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
14113 * @class Roo.bootstrap.Radio
14114 * @extends Roo.bootstrap.CheckBox
14115 * Bootstrap Radio class
14118 * Create a new Radio
14119 * @param {Object} config The config object
14122 Roo.bootstrap.Radio = function(config){
14123 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
14127 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
14129 inputType: 'radio',
14133 getAutoCreate : function()
14135 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
14141 cfg.cls = 'form-group radio' //input-group
14146 type : this.inputType,
14147 value : (!this.checked) ? this.valueOff : this.inputValue,
14149 placeholder : this.placeholder || ''
14152 if (this.weight) { // Validity check?
14153 cfg.cls += " radio-" + this.weight;
14155 if (this.disabled) {
14156 input.disabled=true;
14160 input.checked = this.checked;
14164 input.name = this.name;
14168 input.cls += ' input-' + this.size;
14172 ['xs','sm','md','lg'].map(function(size){
14173 if (settings[size]) {
14174 cfg.cls += ' col-' + size + '-' + settings[size];
14178 var inputblock = input;
14180 if (this.before || this.after) {
14183 cls : 'input-group',
14187 inputblock.cn.push({
14189 cls : 'input-group-addon',
14193 inputblock.cn.push(input);
14195 inputblock.cn.push({
14197 cls : 'input-group-addon',
14204 if (align ==='left' && this.fieldLabel.length) {
14205 Roo.log("left and has label");
14211 cls : 'control-label col-md-' + this.labelWidth,
14212 html : this.fieldLabel
14216 cls : "col-md-" + (12 - this.labelWidth),
14223 } else if ( this.fieldLabel.length) {
14230 cls: 'control-label box-input-label',
14231 //cls : 'input-group-addon',
14232 html : this.fieldLabel
14242 Roo.log(" no label && no align");
14257 html: this.boxLabel
14264 inputEl: function ()
14266 return this.el.select('input.roo-radio',true).first();
14268 onClick : function()
14270 this.setChecked(true);
14273 setChecked : function(state,suppressEvent)
14276 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
14277 v.dom.checked = false;
14281 this.checked = state;
14282 this.inputEl().dom.checked = state;
14284 if(suppressEvent !== true){
14285 this.fireEvent('check', this, state);
14288 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
14292 getGroupValue : function()
14295 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
14296 if(v.dom.checked == true){
14297 value = v.dom.value;
14305 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
14306 * @return {Mixed} value The field value
14308 getValue : function(){
14309 return this.getGroupValue();
14315 //<script type="text/javascript">
14318 * Based Ext JS Library 1.1.1
14319 * Copyright(c) 2006-2007, Ext JS, LLC.
14325 * @class Roo.HtmlEditorCore
14326 * @extends Roo.Component
14327 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
14329 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
14332 Roo.HtmlEditorCore = function(config){
14335 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
14338 * @event initialize
14339 * Fires when the editor is fully initialized (including the iframe)
14340 * @param {Roo.HtmlEditorCore} this
14345 * Fires when the editor is first receives the focus. Any insertion must wait
14346 * until after this event.
14347 * @param {Roo.HtmlEditorCore} this
14351 * @event beforesync
14352 * Fires before the textarea is updated with content from the editor iframe. Return false
14353 * to cancel the sync.
14354 * @param {Roo.HtmlEditorCore} this
14355 * @param {String} html
14359 * @event beforepush
14360 * Fires before the iframe editor is updated with content from the textarea. Return false
14361 * to cancel the push.
14362 * @param {Roo.HtmlEditorCore} this
14363 * @param {String} html
14368 * Fires when the textarea is updated with content from the editor iframe.
14369 * @param {Roo.HtmlEditorCore} this
14370 * @param {String} html
14375 * Fires when the iframe editor is updated with content from the textarea.
14376 * @param {Roo.HtmlEditorCore} this
14377 * @param {String} html
14382 * @event editorevent
14383 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
14384 * @param {Roo.HtmlEditorCore} this
14392 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
14396 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
14402 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
14407 * @cfg {Number} height (in pixels)
14411 * @cfg {Number} width (in pixels)
14416 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
14419 stylesheets: false,
14424 // private properties
14425 validationEvent : false,
14427 initialized : false,
14429 sourceEditMode : false,
14430 onFocus : Roo.emptyFn,
14432 hideMode:'offsets',
14440 * Protected method that will not generally be called directly. It
14441 * is called when the editor initializes the iframe with HTML contents. Override this method if you
14442 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
14444 getDocMarkup : function(){
14447 Roo.log(this.stylesheets);
14449 // inherit styels from page...??
14450 if (this.stylesheets === false) {
14452 Roo.get(document.head).select('style').each(function(node) {
14453 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
14456 Roo.get(document.head).select('link').each(function(node) {
14457 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
14460 } else if (!this.stylesheets.length) {
14462 st = '<style type="text/css">' +
14463 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
14466 Roo.each(this.stylesheets, function(s) {
14467 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
14472 st += '<style type="text/css">' +
14473 'IMG { cursor: pointer } ' +
14477 return '<html><head>' + st +
14478 //<style type="text/css">' +
14479 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
14481 ' </head><body class="roo-htmleditor-body"></body></html>';
14485 onRender : function(ct, position)
14488 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
14489 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
14492 this.el.dom.style.border = '0 none';
14493 this.el.dom.setAttribute('tabIndex', -1);
14494 this.el.addClass('x-hidden hide');
14498 if(Roo.isIE){ // fix IE 1px bogus margin
14499 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
14503 this.frameId = Roo.id();
14507 var iframe = this.owner.wrap.createChild({
14509 cls: 'form-control', // bootstrap..
14511 name: this.frameId,
14512 frameBorder : 'no',
14513 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
14518 this.iframe = iframe.dom;
14520 this.assignDocWin();
14522 this.doc.designMode = 'on';
14525 this.doc.write(this.getDocMarkup());
14529 var task = { // must defer to wait for browser to be ready
14531 //console.log("run task?" + this.doc.readyState);
14532 this.assignDocWin();
14533 if(this.doc.body || this.doc.readyState == 'complete'){
14535 this.doc.designMode="on";
14539 Roo.TaskMgr.stop(task);
14540 this.initEditor.defer(10, this);
14547 Roo.TaskMgr.start(task);
14554 onResize : function(w, h)
14556 Roo.log('resize: ' +w + ',' + h );
14557 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
14561 if(typeof w == 'number'){
14563 this.iframe.style.width = w + 'px';
14565 if(typeof h == 'number'){
14567 this.iframe.style.height = h + 'px';
14569 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
14576 * Toggles the editor between standard and source edit mode.
14577 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
14579 toggleSourceEdit : function(sourceEditMode){
14581 this.sourceEditMode = sourceEditMode === true;
14583 if(this.sourceEditMode){
14585 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
14588 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
14589 //this.iframe.className = '';
14592 //this.setSize(this.owner.wrap.getSize());
14593 //this.fireEvent('editmodechange', this, this.sourceEditMode);
14600 * Protected method that will not generally be called directly. If you need/want
14601 * custom HTML cleanup, this is the method you should override.
14602 * @param {String} html The HTML to be cleaned
14603 * return {String} The cleaned HTML
14605 cleanHtml : function(html){
14606 html = String(html);
14607 if(html.length > 5){
14608 if(Roo.isSafari){ // strip safari nonsense
14609 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
14612 if(html == ' '){
14619 * HTML Editor -> Textarea
14620 * Protected method that will not generally be called directly. Syncs the contents
14621 * of the editor iframe with the textarea.
14623 syncValue : function(){
14624 if(this.initialized){
14625 var bd = (this.doc.body || this.doc.documentElement);
14626 //this.cleanUpPaste(); -- this is done else where and causes havoc..
14627 var html = bd.innerHTML;
14629 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
14630 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
14632 html = '<div style="'+m[0]+'">' + html + '</div>';
14635 html = this.cleanHtml(html);
14636 // fix up the special chars.. normaly like back quotes in word...
14637 // however we do not want to do this with chinese..
14638 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
14639 var cc = b.charCodeAt();
14641 (cc >= 0x4E00 && cc < 0xA000 ) ||
14642 (cc >= 0x3400 && cc < 0x4E00 ) ||
14643 (cc >= 0xf900 && cc < 0xfb00 )
14649 if(this.owner.fireEvent('beforesync', this, html) !== false){
14650 this.el.dom.value = html;
14651 this.owner.fireEvent('sync', this, html);
14657 * Protected method that will not generally be called directly. Pushes the value of the textarea
14658 * into the iframe editor.
14660 pushValue : function(){
14661 if(this.initialized){
14662 var v = this.el.dom.value.trim();
14664 // if(v.length < 1){
14668 if(this.owner.fireEvent('beforepush', this, v) !== false){
14669 var d = (this.doc.body || this.doc.documentElement);
14671 this.cleanUpPaste();
14672 this.el.dom.value = d.innerHTML;
14673 this.owner.fireEvent('push', this, v);
14679 deferFocus : function(){
14680 this.focus.defer(10, this);
14684 focus : function(){
14685 if(this.win && !this.sourceEditMode){
14692 assignDocWin: function()
14694 var iframe = this.iframe;
14697 this.doc = iframe.contentWindow.document;
14698 this.win = iframe.contentWindow;
14700 if (!Roo.get(this.frameId)) {
14703 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
14704 this.win = Roo.get(this.frameId).dom.contentWindow;
14709 initEditor : function(){
14710 //console.log("INIT EDITOR");
14711 this.assignDocWin();
14715 this.doc.designMode="on";
14717 this.doc.write(this.getDocMarkup());
14720 var dbody = (this.doc.body || this.doc.documentElement);
14721 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
14722 // this copies styles from the containing element into thsi one..
14723 // not sure why we need all of this..
14724 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
14726 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
14727 //ss['background-attachment'] = 'fixed'; // w3c
14728 dbody.bgProperties = 'fixed'; // ie
14729 //Roo.DomHelper.applyStyles(dbody, ss);
14730 Roo.EventManager.on(this.doc, {
14731 //'mousedown': this.onEditorEvent,
14732 'mouseup': this.onEditorEvent,
14733 'dblclick': this.onEditorEvent,
14734 'click': this.onEditorEvent,
14735 'keyup': this.onEditorEvent,
14740 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
14742 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
14743 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
14745 this.initialized = true;
14747 this.owner.fireEvent('initialize', this);
14752 onDestroy : function(){
14758 //for (var i =0; i < this.toolbars.length;i++) {
14759 // // fixme - ask toolbars for heights?
14760 // this.toolbars[i].onDestroy();
14763 //this.wrap.dom.innerHTML = '';
14764 //this.wrap.remove();
14769 onFirstFocus : function(){
14771 this.assignDocWin();
14774 this.activated = true;
14777 if(Roo.isGecko){ // prevent silly gecko errors
14779 var s = this.win.getSelection();
14780 if(!s.focusNode || s.focusNode.nodeType != 3){
14781 var r = s.getRangeAt(0);
14782 r.selectNodeContents((this.doc.body || this.doc.documentElement));
14787 this.execCmd('useCSS', true);
14788 this.execCmd('styleWithCSS', false);
14791 this.owner.fireEvent('activate', this);
14795 adjustFont: function(btn){
14796 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
14797 //if(Roo.isSafari){ // safari
14800 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
14801 if(Roo.isSafari){ // safari
14802 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
14803 v = (v < 10) ? 10 : v;
14804 v = (v > 48) ? 48 : v;
14805 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
14810 v = Math.max(1, v+adjust);
14812 this.execCmd('FontSize', v );
14815 onEditorEvent : function(e){
14816 this.owner.fireEvent('editorevent', this, e);
14817 // this.updateToolbar();
14818 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
14821 insertTag : function(tg)
14823 // could be a bit smarter... -> wrap the current selected tRoo..
14824 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
14826 range = this.createRange(this.getSelection());
14827 var wrappingNode = this.doc.createElement(tg.toLowerCase());
14828 wrappingNode.appendChild(range.extractContents());
14829 range.insertNode(wrappingNode);
14836 this.execCmd("formatblock", tg);
14840 insertText : function(txt)
14844 var range = this.createRange();
14845 range.deleteContents();
14846 //alert(Sender.getAttribute('label'));
14848 range.insertNode(this.doc.createTextNode(txt));
14854 * Executes a Midas editor command on the editor document and performs necessary focus and
14855 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
14856 * @param {String} cmd The Midas command
14857 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
14859 relayCmd : function(cmd, value){
14861 this.execCmd(cmd, value);
14862 this.owner.fireEvent('editorevent', this);
14863 //this.updateToolbar();
14864 this.owner.deferFocus();
14868 * Executes a Midas editor command directly on the editor document.
14869 * For visual commands, you should use {@link #relayCmd} instead.
14870 * <b>This should only be called after the editor is initialized.</b>
14871 * @param {String} cmd The Midas command
14872 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
14874 execCmd : function(cmd, value){
14875 this.doc.execCommand(cmd, false, value === undefined ? null : value);
14882 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
14884 * @param {String} text | dom node..
14886 insertAtCursor : function(text)
14891 if(!this.activated){
14897 var r = this.doc.selection.createRange();
14908 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
14912 // from jquery ui (MIT licenced)
14914 var win = this.win;
14916 if (win.getSelection && win.getSelection().getRangeAt) {
14917 range = win.getSelection().getRangeAt(0);
14918 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
14919 range.insertNode(node);
14920 } else if (win.document.selection && win.document.selection.createRange) {
14921 // no firefox support
14922 var txt = typeof(text) == 'string' ? text : text.outerHTML;
14923 win.document.selection.createRange().pasteHTML(txt);
14925 // no firefox support
14926 var txt = typeof(text) == 'string' ? text : text.outerHTML;
14927 this.execCmd('InsertHTML', txt);
14936 mozKeyPress : function(e){
14938 var c = e.getCharCode(), cmd;
14941 c = String.fromCharCode(c).toLowerCase();
14955 this.cleanUpPaste.defer(100, this);
14963 e.preventDefault();
14971 fixKeys : function(){ // load time branching for fastest keydown performance
14973 return function(e){
14974 var k = e.getKey(), r;
14977 r = this.doc.selection.createRange();
14980 r.pasteHTML('    ');
14987 r = this.doc.selection.createRange();
14989 var target = r.parentElement();
14990 if(!target || target.tagName.toLowerCase() != 'li'){
14992 r.pasteHTML('<br />');
14998 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
14999 this.cleanUpPaste.defer(100, this);
15005 }else if(Roo.isOpera){
15006 return function(e){
15007 var k = e.getKey();
15011 this.execCmd('InsertHTML','    ');
15014 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
15015 this.cleanUpPaste.defer(100, this);
15020 }else if(Roo.isSafari){
15021 return function(e){
15022 var k = e.getKey();
15026 this.execCmd('InsertText','\t');
15030 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
15031 this.cleanUpPaste.defer(100, this);
15039 getAllAncestors: function()
15041 var p = this.getSelectedNode();
15044 a.push(p); // push blank onto stack..
15045 p = this.getParentElement();
15049 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
15053 a.push(this.doc.body);
15057 lastSelNode : false,
15060 getSelection : function()
15062 this.assignDocWin();
15063 return Roo.isIE ? this.doc.selection : this.win.getSelection();
15066 getSelectedNode: function()
15068 // this may only work on Gecko!!!
15070 // should we cache this!!!!
15075 var range = this.createRange(this.getSelection()).cloneRange();
15078 var parent = range.parentElement();
15080 var testRange = range.duplicate();
15081 testRange.moveToElementText(parent);
15082 if (testRange.inRange(range)) {
15085 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
15088 parent = parent.parentElement;
15093 // is ancestor a text element.
15094 var ac = range.commonAncestorContainer;
15095 if (ac.nodeType == 3) {
15096 ac = ac.parentNode;
15099 var ar = ac.childNodes;
15102 var other_nodes = [];
15103 var has_other_nodes = false;
15104 for (var i=0;i<ar.length;i++) {
15105 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
15108 // fullly contained node.
15110 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
15115 // probably selected..
15116 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
15117 other_nodes.push(ar[i]);
15121 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
15126 has_other_nodes = true;
15128 if (!nodes.length && other_nodes.length) {
15129 nodes= other_nodes;
15131 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
15137 createRange: function(sel)
15139 // this has strange effects when using with
15140 // top toolbar - not sure if it's a great idea.
15141 //this.editor.contentWindow.focus();
15142 if (typeof sel != "undefined") {
15144 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
15146 return this.doc.createRange();
15149 return this.doc.createRange();
15152 getParentElement: function()
15155 this.assignDocWin();
15156 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
15158 var range = this.createRange(sel);
15161 var p = range.commonAncestorContainer;
15162 while (p.nodeType == 3) { // text node
15173 * Range intersection.. the hard stuff...
15177 * [ -- selected range --- ]
15181 * if end is before start or hits it. fail.
15182 * if start is after end or hits it fail.
15184 * if either hits (but other is outside. - then it's not
15190 // @see http://www.thismuchiknow.co.uk/?p=64.
15191 rangeIntersectsNode : function(range, node)
15193 var nodeRange = node.ownerDocument.createRange();
15195 nodeRange.selectNode(node);
15197 nodeRange.selectNodeContents(node);
15200 var rangeStartRange = range.cloneRange();
15201 rangeStartRange.collapse(true);
15203 var rangeEndRange = range.cloneRange();
15204 rangeEndRange.collapse(false);
15206 var nodeStartRange = nodeRange.cloneRange();
15207 nodeStartRange.collapse(true);
15209 var nodeEndRange = nodeRange.cloneRange();
15210 nodeEndRange.collapse(false);
15212 return rangeStartRange.compareBoundaryPoints(
15213 Range.START_TO_START, nodeEndRange) == -1 &&
15214 rangeEndRange.compareBoundaryPoints(
15215 Range.START_TO_START, nodeStartRange) == 1;
15219 rangeCompareNode : function(range, node)
15221 var nodeRange = node.ownerDocument.createRange();
15223 nodeRange.selectNode(node);
15225 nodeRange.selectNodeContents(node);
15229 range.collapse(true);
15231 nodeRange.collapse(true);
15233 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
15234 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
15236 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
15238 var nodeIsBefore = ss == 1;
15239 var nodeIsAfter = ee == -1;
15241 if (nodeIsBefore && nodeIsAfter)
15243 if (!nodeIsBefore && nodeIsAfter)
15244 return 1; //right trailed.
15246 if (nodeIsBefore && !nodeIsAfter)
15247 return 2; // left trailed.
15252 // private? - in a new class?
15253 cleanUpPaste : function()
15255 // cleans up the whole document..
15256 Roo.log('cleanuppaste');
15258 this.cleanUpChildren(this.doc.body);
15259 var clean = this.cleanWordChars(this.doc.body.innerHTML);
15260 if (clean != this.doc.body.innerHTML) {
15261 this.doc.body.innerHTML = clean;
15266 cleanWordChars : function(input) {// change the chars to hex code
15267 var he = Roo.HtmlEditorCore;
15269 var output = input;
15270 Roo.each(he.swapCodes, function(sw) {
15271 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
15273 output = output.replace(swapper, sw[1]);
15280 cleanUpChildren : function (n)
15282 if (!n.childNodes.length) {
15285 for (var i = n.childNodes.length-1; i > -1 ; i--) {
15286 this.cleanUpChild(n.childNodes[i]);
15293 cleanUpChild : function (node)
15296 //console.log(node);
15297 if (node.nodeName == "#text") {
15298 // clean up silly Windows -- stuff?
15301 if (node.nodeName == "#comment") {
15302 node.parentNode.removeChild(node);
15303 // clean up silly Windows -- stuff?
15307 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
15309 node.parentNode.removeChild(node);
15314 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
15316 // remove <a name=....> as rendering on yahoo mailer is borked with this.
15317 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
15319 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
15320 // remove_keep_children = true;
15323 if (remove_keep_children) {
15324 this.cleanUpChildren(node);
15325 // inserts everything just before this node...
15326 while (node.childNodes.length) {
15327 var cn = node.childNodes[0];
15328 node.removeChild(cn);
15329 node.parentNode.insertBefore(cn, node);
15331 node.parentNode.removeChild(node);
15335 if (!node.attributes || !node.attributes.length) {
15336 this.cleanUpChildren(node);
15340 function cleanAttr(n,v)
15343 if (v.match(/^\./) || v.match(/^\//)) {
15346 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
15349 if (v.match(/^#/)) {
15352 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
15353 node.removeAttribute(n);
15357 function cleanStyle(n,v)
15359 if (v.match(/expression/)) { //XSS?? should we even bother..
15360 node.removeAttribute(n);
15363 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
15364 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
15367 var parts = v.split(/;/);
15370 Roo.each(parts, function(p) {
15371 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
15375 var l = p.split(':').shift().replace(/\s+/g,'');
15376 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
15378 if ( cblack.indexOf(l) > -1) {
15379 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
15380 //node.removeAttribute(n);
15384 // only allow 'c whitelisted system attributes'
15385 if ( cwhite.length && cwhite.indexOf(l) < 0) {
15386 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
15387 //node.removeAttribute(n);
15397 if (clean.length) {
15398 node.setAttribute(n, clean.join(';'));
15400 node.removeAttribute(n);
15406 for (var i = node.attributes.length-1; i > -1 ; i--) {
15407 var a = node.attributes[i];
15410 if (a.name.toLowerCase().substr(0,2)=='on') {
15411 node.removeAttribute(a.name);
15414 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
15415 node.removeAttribute(a.name);
15418 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
15419 cleanAttr(a.name,a.value); // fixme..
15422 if (a.name == 'style') {
15423 cleanStyle(a.name,a.value);
15426 /// clean up MS crap..
15427 // tecnically this should be a list of valid class'es..
15430 if (a.name == 'class') {
15431 if (a.value.match(/^Mso/)) {
15432 node.className = '';
15435 if (a.value.match(/body/)) {
15436 node.className = '';
15447 this.cleanUpChildren(node);
15452 * Clean up MS wordisms...
15454 cleanWord : function(node)
15457 var cleanWordChildren = function()
15459 if (!node.childNodes.length) {
15462 for (var i = node.childNodes.length-1; i > -1 ; i--) {
15463 _t.cleanWord(node.childNodes[i]);
15469 this.cleanWord(this.doc.body);
15472 if (node.nodeName == "#text") {
15473 // clean up silly Windows -- stuff?
15476 if (node.nodeName == "#comment") {
15477 node.parentNode.removeChild(node);
15478 // clean up silly Windows -- stuff?
15482 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
15483 node.parentNode.removeChild(node);
15487 // remove - but keep children..
15488 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
15489 while (node.childNodes.length) {
15490 var cn = node.childNodes[0];
15491 node.removeChild(cn);
15492 node.parentNode.insertBefore(cn, node);
15494 node.parentNode.removeChild(node);
15495 cleanWordChildren();
15499 if (node.className.length) {
15501 var cn = node.className.split(/\W+/);
15503 Roo.each(cn, function(cls) {
15504 if (cls.match(/Mso[a-zA-Z]+/)) {
15509 node.className = cna.length ? cna.join(' ') : '';
15511 node.removeAttribute("class");
15515 if (node.hasAttribute("lang")) {
15516 node.removeAttribute("lang");
15519 if (node.hasAttribute("style")) {
15521 var styles = node.getAttribute("style").split(";");
15523 Roo.each(styles, function(s) {
15524 if (!s.match(/:/)) {
15527 var kv = s.split(":");
15528 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
15531 // what ever is left... we allow.
15534 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
15535 if (!nstyle.length) {
15536 node.removeAttribute('style');
15540 cleanWordChildren();
15544 domToHTML : function(currentElement, depth, nopadtext) {
15546 depth = depth || 0;
15547 nopadtext = nopadtext || false;
15549 if (!currentElement) {
15550 return this.domToHTML(this.doc.body);
15553 //Roo.log(currentElement);
15555 var allText = false;
15556 var nodeName = currentElement.nodeName;
15557 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
15559 if (nodeName == '#text') {
15560 return currentElement.nodeValue;
15565 if (nodeName != 'BODY') {
15568 // Prints the node tagName, such as <A>, <IMG>, etc
15571 for(i = 0; i < currentElement.attributes.length;i++) {
15573 var aname = currentElement.attributes.item(i).name;
15574 if (!currentElement.attributes.item(i).value.length) {
15577 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
15580 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
15589 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
15592 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
15597 // Traverse the tree
15599 var currentElementChild = currentElement.childNodes.item(i);
15600 var allText = true;
15601 var innerHTML = '';
15603 while (currentElementChild) {
15604 // Formatting code (indent the tree so it looks nice on the screen)
15605 var nopad = nopadtext;
15606 if (lastnode == 'SPAN') {
15610 if (currentElementChild.nodeName == '#text') {
15611 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
15612 if (!nopad && toadd.length > 80) {
15613 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
15615 innerHTML += toadd;
15618 currentElementChild = currentElement.childNodes.item(i);
15624 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
15626 // Recursively traverse the tree structure of the child node
15627 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
15628 lastnode = currentElementChild.nodeName;
15630 currentElementChild=currentElement.childNodes.item(i);
15636 // The remaining code is mostly for formatting the tree
15637 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
15642 ret+= "</"+tagName+">";
15648 // hide stuff that is not compatible
15662 * @event specialkey
15666 * @cfg {String} fieldClass @hide
15669 * @cfg {String} focusClass @hide
15672 * @cfg {String} autoCreate @hide
15675 * @cfg {String} inputType @hide
15678 * @cfg {String} invalidClass @hide
15681 * @cfg {String} invalidText @hide
15684 * @cfg {String} msgFx @hide
15687 * @cfg {String} validateOnBlur @hide
15691 Roo.HtmlEditorCore.white = [
15692 'area', 'br', 'img', 'input', 'hr', 'wbr',
15694 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
15695 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
15696 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
15697 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
15698 'table', 'ul', 'xmp',
15700 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
15703 'dir', 'menu', 'ol', 'ul', 'dl',
15709 Roo.HtmlEditorCore.black = [
15710 // 'embed', 'object', // enable - backend responsiblity to clean thiese
15712 'base', 'basefont', 'bgsound', 'blink', 'body',
15713 'frame', 'frameset', 'head', 'html', 'ilayer',
15714 'iframe', 'layer', 'link', 'meta', 'object',
15715 'script', 'style' ,'title', 'xml' // clean later..
15717 Roo.HtmlEditorCore.clean = [
15718 'script', 'style', 'title', 'xml'
15720 Roo.HtmlEditorCore.remove = [
15725 Roo.HtmlEditorCore.ablack = [
15729 Roo.HtmlEditorCore.aclean = [
15730 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
15734 Roo.HtmlEditorCore.pwhite= [
15735 'http', 'https', 'mailto'
15738 // white listed style attributes.
15739 Roo.HtmlEditorCore.cwhite= [
15740 // 'text-align', /// default is to allow most things..
15746 // black listed style attributes.
15747 Roo.HtmlEditorCore.cblack= [
15748 // 'font-size' -- this can be set by the project
15752 Roo.HtmlEditorCore.swapCodes =[
15771 * @class Roo.bootstrap.HtmlEditor
15772 * @extends Roo.bootstrap.TextArea
15773 * Bootstrap HtmlEditor class
15776 * Create a new HtmlEditor
15777 * @param {Object} config The config object
15780 Roo.bootstrap.HtmlEditor = function(config){
15781 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
15782 if (!this.toolbars) {
15783 this.toolbars = [];
15785 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
15788 * @event initialize
15789 * Fires when the editor is fully initialized (including the iframe)
15790 * @param {HtmlEditor} this
15795 * Fires when the editor is first receives the focus. Any insertion must wait
15796 * until after this event.
15797 * @param {HtmlEditor} this
15801 * @event beforesync
15802 * Fires before the textarea is updated with content from the editor iframe. Return false
15803 * to cancel the sync.
15804 * @param {HtmlEditor} this
15805 * @param {String} html
15809 * @event beforepush
15810 * Fires before the iframe editor is updated with content from the textarea. Return false
15811 * to cancel the push.
15812 * @param {HtmlEditor} this
15813 * @param {String} html
15818 * Fires when the textarea is updated with content from the editor iframe.
15819 * @param {HtmlEditor} this
15820 * @param {String} html
15825 * Fires when the iframe editor is updated with content from the textarea.
15826 * @param {HtmlEditor} this
15827 * @param {String} html
15831 * @event editmodechange
15832 * Fires when the editor switches edit modes
15833 * @param {HtmlEditor} this
15834 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
15836 editmodechange: true,
15838 * @event editorevent
15839 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
15840 * @param {HtmlEditor} this
15844 * @event firstfocus
15845 * Fires when on first focus - needed by toolbars..
15846 * @param {HtmlEditor} this
15851 * Auto save the htmlEditor value as a file into Events
15852 * @param {HtmlEditor} this
15856 * @event savedpreview
15857 * preview the saved version of htmlEditor
15858 * @param {HtmlEditor} this
15865 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
15869 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
15874 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
15879 * @cfg {Number} height (in pixels)
15883 * @cfg {Number} width (in pixels)
15888 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
15891 stylesheets: false,
15896 // private properties
15897 validationEvent : false,
15899 initialized : false,
15902 onFocus : Roo.emptyFn,
15904 hideMode:'offsets',
15907 tbContainer : false,
15909 toolbarContainer :function() {
15910 return this.wrap.select('.x-html-editor-tb',true).first();
15914 * Protected method that will not generally be called directly. It
15915 * is called when the editor creates its toolbar. Override this method if you need to
15916 * add custom toolbar buttons.
15917 * @param {HtmlEditor} editor
15919 createToolbar : function(){
15921 Roo.log("create toolbars");
15923 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
15924 this.toolbars[0].render(this.toolbarContainer());
15928 // if (!editor.toolbars || !editor.toolbars.length) {
15929 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
15932 // for (var i =0 ; i < editor.toolbars.length;i++) {
15933 // editor.toolbars[i] = Roo.factory(
15934 // typeof(editor.toolbars[i]) == 'string' ?
15935 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
15936 // Roo.bootstrap.HtmlEditor);
15937 // editor.toolbars[i].init(editor);
15943 onRender : function(ct, position)
15945 // Roo.log("Call onRender: " + this.xtype);
15947 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
15949 this.wrap = this.inputEl().wrap({
15950 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
15953 this.editorcore.onRender(ct, position);
15955 if (this.resizable) {
15956 this.resizeEl = new Roo.Resizable(this.wrap, {
15960 minHeight : this.height,
15961 height: this.height,
15962 handles : this.resizable,
15965 resize : function(r, w, h) {
15966 _t.onResize(w,h); // -something
15972 this.createToolbar(this);
15975 if(!this.width && this.resizable){
15976 this.setSize(this.wrap.getSize());
15978 if (this.resizeEl) {
15979 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
15980 // should trigger onReize..
15986 onResize : function(w, h)
15988 Roo.log('resize: ' +w + ',' + h );
15989 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
15993 if(this.inputEl() ){
15994 if(typeof w == 'number'){
15995 var aw = w - this.wrap.getFrameWidth('lr');
15996 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
15999 if(typeof h == 'number'){
16000 var tbh = -11; // fixme it needs to tool bar size!
16001 for (var i =0; i < this.toolbars.length;i++) {
16002 // fixme - ask toolbars for heights?
16003 tbh += this.toolbars[i].el.getHeight();
16004 //if (this.toolbars[i].footer) {
16005 // tbh += this.toolbars[i].footer.el.getHeight();
16013 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
16014 ah -= 5; // knock a few pixes off for look..
16015 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
16019 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
16020 this.editorcore.onResize(ew,eh);
16025 * Toggles the editor between standard and source edit mode.
16026 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16028 toggleSourceEdit : function(sourceEditMode)
16030 this.editorcore.toggleSourceEdit(sourceEditMode);
16032 if(this.editorcore.sourceEditMode){
16033 Roo.log('editor - showing textarea');
16036 // Roo.log(this.syncValue());
16038 this.inputEl().removeClass('hide');
16039 this.inputEl().dom.removeAttribute('tabIndex');
16040 this.inputEl().focus();
16042 Roo.log('editor - hiding textarea');
16044 // Roo.log(this.pushValue());
16047 this.inputEl().addClass('hide');
16048 this.inputEl().dom.setAttribute('tabIndex', -1);
16049 //this.deferFocus();
16052 if(this.resizable){
16053 this.setSize(this.wrap.getSize());
16056 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
16059 // private (for BoxComponent)
16060 adjustSize : Roo.BoxComponent.prototype.adjustSize,
16062 // private (for BoxComponent)
16063 getResizeEl : function(){
16067 // private (for BoxComponent)
16068 getPositionEl : function(){
16073 initEvents : function(){
16074 this.originalValue = this.getValue();
16078 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
16081 // markInvalid : Roo.emptyFn,
16083 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
16086 // clearInvalid : Roo.emptyFn,
16088 setValue : function(v){
16089 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
16090 this.editorcore.pushValue();
16095 deferFocus : function(){
16096 this.focus.defer(10, this);
16100 focus : function(){
16101 this.editorcore.focus();
16107 onDestroy : function(){
16113 for (var i =0; i < this.toolbars.length;i++) {
16114 // fixme - ask toolbars for heights?
16115 this.toolbars[i].onDestroy();
16118 this.wrap.dom.innerHTML = '';
16119 this.wrap.remove();
16124 onFirstFocus : function(){
16125 //Roo.log("onFirstFocus");
16126 this.editorcore.onFirstFocus();
16127 for (var i =0; i < this.toolbars.length;i++) {
16128 this.toolbars[i].onFirstFocus();
16134 syncValue : function()
16136 this.editorcore.syncValue();
16139 pushValue : function()
16141 this.editorcore.pushValue();
16145 // hide stuff that is not compatible
16159 * @event specialkey
16163 * @cfg {String} fieldClass @hide
16166 * @cfg {String} focusClass @hide
16169 * @cfg {String} autoCreate @hide
16172 * @cfg {String} inputType @hide
16175 * @cfg {String} invalidClass @hide
16178 * @cfg {String} invalidText @hide
16181 * @cfg {String} msgFx @hide
16184 * @cfg {String} validateOnBlur @hide
16193 Roo.namespace('Roo.bootstrap.htmleditor');
16195 * @class Roo.bootstrap.HtmlEditorToolbar1
16200 new Roo.bootstrap.HtmlEditor({
16203 new Roo.bootstrap.HtmlEditorToolbar1({
16204 disable : { fonts: 1 , format: 1, ..., ... , ...],
16210 * @cfg {Object} disable List of elements to disable..
16211 * @cfg {Array} btns List of additional buttons.
16215 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
16218 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
16221 Roo.apply(this, config);
16223 // default disabled, based on 'good practice'..
16224 this.disable = this.disable || {};
16225 Roo.applyIf(this.disable, {
16228 specialElements : true
16230 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
16232 this.editor = config.editor;
16233 this.editorcore = config.editor.editorcore;
16235 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
16237 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
16238 // dont call parent... till later.
16240 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
16245 editorcore : false,
16250 "h1","h2","h3","h4","h5","h6",
16252 "abbr", "acronym", "address", "cite", "samp", "var",
16256 onRender : function(ct, position)
16258 // Roo.log("Call onRender: " + this.xtype);
16260 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
16262 this.el.dom.style.marginBottom = '0';
16264 var editorcore = this.editorcore;
16265 var editor= this.editor;
16268 var btn = function(id,cmd , toggle, handler){
16270 var event = toggle ? 'toggle' : 'click';
16275 xns: Roo.bootstrap,
16278 enableToggle:toggle !== false,
16280 pressed : toggle ? false : null,
16283 a.listeners[toggle ? 'toggle' : 'click'] = function() {
16284 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
16293 xns: Roo.bootstrap,
16294 glyphicon : 'font',
16298 xns: Roo.bootstrap,
16302 Roo.each(this.formats, function(f) {
16303 style.menu.items.push({
16305 xns: Roo.bootstrap,
16306 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
16311 editorcore.insertTag(this.tagname);
16318 children.push(style);
16321 btn('bold',false,true);
16322 btn('italic',false,true);
16323 btn('align-left', 'justifyleft',true);
16324 btn('align-center', 'justifycenter',true);
16325 btn('align-right' , 'justifyright',true);
16326 btn('link', false, false, function(btn) {
16327 //Roo.log("create link?");
16328 var url = prompt(this.createLinkText, this.defaultLinkValue);
16329 if(url && url != 'http:/'+'/'){
16330 this.editorcore.relayCmd('createlink', url);
16333 btn('list','insertunorderedlist',true);
16334 btn('pencil', false,true, function(btn){
16337 this.toggleSourceEdit(btn.pressed);
16343 xns: Roo.bootstrap,
16348 xns: Roo.bootstrap,
16353 cog.menu.items.push({
16355 xns: Roo.bootstrap,
16356 html : Clean styles,
16361 editorcore.insertTag(this.tagname);
16370 this.xtype = 'NavSimplebar';
16372 for(var i=0;i< children.length;i++) {
16374 this.buttons.add(this.addxtypeChild(children[i]));
16378 editor.on('editorevent', this.updateToolbar, this);
16380 onBtnClick : function(id)
16382 this.editorcore.relayCmd(id);
16383 this.editorcore.focus();
16387 * Protected method that will not generally be called directly. It triggers
16388 * a toolbar update by reading the markup state of the current selection in the editor.
16390 updateToolbar: function(){
16392 if(!this.editorcore.activated){
16393 this.editor.onFirstFocus(); // is this neeed?
16397 var btns = this.buttons;
16398 var doc = this.editorcore.doc;
16399 btns.get('bold').setActive(doc.queryCommandState('bold'));
16400 btns.get('italic').setActive(doc.queryCommandState('italic'));
16401 //btns.get('underline').setActive(doc.queryCommandState('underline'));
16403 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
16404 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
16405 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
16407 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
16408 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
16411 var ans = this.editorcore.getAllAncestors();
16412 if (this.formatCombo) {
16415 var store = this.formatCombo.store;
16416 this.formatCombo.setValue("");
16417 for (var i =0; i < ans.length;i++) {
16418 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
16420 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
16428 // hides menus... - so this cant be on a menu...
16429 Roo.bootstrap.MenuMgr.hideAll();
16431 Roo.bootstrap.MenuMgr.hideAll();
16432 //this.editorsyncValue();
16434 onFirstFocus: function() {
16435 this.buttons.each(function(item){
16439 toggleSourceEdit : function(sourceEditMode){
16442 if(sourceEditMode){
16443 Roo.log("disabling buttons");
16444 this.buttons.each( function(item){
16445 if(item.cmd != 'pencil'){
16451 Roo.log("enabling buttons");
16452 if(this.editorcore.initialized){
16453 this.buttons.each( function(item){
16459 Roo.log("calling toggole on editor");
16460 // tell the editor that it's been pressed..
16461 this.editor.toggleSourceEdit(sourceEditMode);
16471 * Ext JS Library 1.1.1
16472 * Copyright(c) 2006-2007, Ext JS, LLC.
16474 * Originally Released Under LGPL - original licence link has changed is not relivant.
16477 * <script type="text/javascript">
16482 * @class Roo.grid.ColumnModel
16483 * @extends Roo.util.Observable
16484 * This is the default implementation of a ColumnModel used by the Grid. It defines
16485 * the columns in the grid.
16488 var colModel = new Roo.grid.ColumnModel([
16489 {header: "Ticker", width: 60, sortable: true, locked: true},
16490 {header: "Company Name", width: 150, sortable: true},
16491 {header: "Market Cap.", width: 100, sortable: true},
16492 {header: "$ Sales", width: 100, sortable: true, renderer: money},
16493 {header: "Employees", width: 100, sortable: true, resizable: false}
16498 * The config options listed for this class are options which may appear in each
16499 * individual column definition.
16500 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
16502 * @param {Object} config An Array of column config objects. See this class's
16503 * config objects for details.
16505 Roo.grid.ColumnModel = function(config){
16507 * The config passed into the constructor
16509 this.config = config;
16512 // if no id, create one
16513 // if the column does not have a dataIndex mapping,
16514 // map it to the order it is in the config
16515 for(var i = 0, len = config.length; i < len; i++){
16517 if(typeof c.dataIndex == "undefined"){
16520 if(typeof c.renderer == "string"){
16521 c.renderer = Roo.util.Format[c.renderer];
16523 if(typeof c.id == "undefined"){
16526 if(c.editor && c.editor.xtype){
16527 c.editor = Roo.factory(c.editor, Roo.grid);
16529 if(c.editor && c.editor.isFormField){
16530 c.editor = new Roo.grid.GridEditor(c.editor);
16532 this.lookup[c.id] = c;
16536 * The width of columns which have no width specified (defaults to 100)
16539 this.defaultWidth = 100;
16542 * Default sortable of columns which have no sortable specified (defaults to false)
16545 this.defaultSortable = false;
16549 * @event widthchange
16550 * Fires when the width of a column changes.
16551 * @param {ColumnModel} this
16552 * @param {Number} columnIndex The column index
16553 * @param {Number} newWidth The new width
16555 "widthchange": true,
16557 * @event headerchange
16558 * Fires when the text of a header changes.
16559 * @param {ColumnModel} this
16560 * @param {Number} columnIndex The column index
16561 * @param {Number} newText The new header text
16563 "headerchange": true,
16565 * @event hiddenchange
16566 * Fires when a column is hidden or "unhidden".
16567 * @param {ColumnModel} this
16568 * @param {Number} columnIndex The column index
16569 * @param {Boolean} hidden true if hidden, false otherwise
16571 "hiddenchange": true,
16573 * @event columnmoved
16574 * Fires when a column is moved.
16575 * @param {ColumnModel} this
16576 * @param {Number} oldIndex
16577 * @param {Number} newIndex
16579 "columnmoved" : true,
16581 * @event columlockchange
16582 * Fires when a column's locked state is changed
16583 * @param {ColumnModel} this
16584 * @param {Number} colIndex
16585 * @param {Boolean} locked true if locked
16587 "columnlockchange" : true
16589 Roo.grid.ColumnModel.superclass.constructor.call(this);
16591 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
16593 * @cfg {String} header The header text to display in the Grid view.
16596 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
16597 * {@link Roo.data.Record} definition from which to draw the column's value. If not
16598 * specified, the column's index is used as an index into the Record's data Array.
16601 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
16602 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
16605 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
16606 * Defaults to the value of the {@link #defaultSortable} property.
16607 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
16610 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
16613 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
16616 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
16619 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
16622 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
16623 * given the cell's data value. See {@link #setRenderer}. If not specified, the
16624 * default renderer uses the raw data value.
16627 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
16630 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
16634 * Returns the id of the column at the specified index.
16635 * @param {Number} index The column index
16636 * @return {String} the id
16638 getColumnId : function(index){
16639 return this.config[index].id;
16643 * Returns the column for a specified id.
16644 * @param {String} id The column id
16645 * @return {Object} the column
16647 getColumnById : function(id){
16648 return this.lookup[id];
16653 * Returns the column for a specified dataIndex.
16654 * @param {String} dataIndex The column dataIndex
16655 * @return {Object|Boolean} the column or false if not found
16657 getColumnByDataIndex: function(dataIndex){
16658 var index = this.findColumnIndex(dataIndex);
16659 return index > -1 ? this.config[index] : false;
16663 * Returns the index for a specified column id.
16664 * @param {String} id The column id
16665 * @return {Number} the index, or -1 if not found
16667 getIndexById : function(id){
16668 for(var i = 0, len = this.config.length; i < len; i++){
16669 if(this.config[i].id == id){
16677 * Returns the index for a specified column dataIndex.
16678 * @param {String} dataIndex The column dataIndex
16679 * @return {Number} the index, or -1 if not found
16682 findColumnIndex : function(dataIndex){
16683 for(var i = 0, len = this.config.length; i < len; i++){
16684 if(this.config[i].dataIndex == dataIndex){
16692 moveColumn : function(oldIndex, newIndex){
16693 var c = this.config[oldIndex];
16694 this.config.splice(oldIndex, 1);
16695 this.config.splice(newIndex, 0, c);
16696 this.dataMap = null;
16697 this.fireEvent("columnmoved", this, oldIndex, newIndex);
16700 isLocked : function(colIndex){
16701 return this.config[colIndex].locked === true;
16704 setLocked : function(colIndex, value, suppressEvent){
16705 if(this.isLocked(colIndex) == value){
16708 this.config[colIndex].locked = value;
16709 if(!suppressEvent){
16710 this.fireEvent("columnlockchange", this, colIndex, value);
16714 getTotalLockedWidth : function(){
16715 var totalWidth = 0;
16716 for(var i = 0; i < this.config.length; i++){
16717 if(this.isLocked(i) && !this.isHidden(i)){
16718 this.totalWidth += this.getColumnWidth(i);
16724 getLockedCount : function(){
16725 for(var i = 0, len = this.config.length; i < len; i++){
16726 if(!this.isLocked(i)){
16733 * Returns the number of columns.
16736 getColumnCount : function(visibleOnly){
16737 if(visibleOnly === true){
16739 for(var i = 0, len = this.config.length; i < len; i++){
16740 if(!this.isHidden(i)){
16746 return this.config.length;
16750 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
16751 * @param {Function} fn
16752 * @param {Object} scope (optional)
16753 * @return {Array} result
16755 getColumnsBy : function(fn, scope){
16757 for(var i = 0, len = this.config.length; i < len; i++){
16758 var c = this.config[i];
16759 if(fn.call(scope||this, c, i) === true){
16767 * Returns true if the specified column is sortable.
16768 * @param {Number} col The column index
16769 * @return {Boolean}
16771 isSortable : function(col){
16772 if(typeof this.config[col].sortable == "undefined"){
16773 return this.defaultSortable;
16775 return this.config[col].sortable;
16779 * Returns the rendering (formatting) function defined for the column.
16780 * @param {Number} col The column index.
16781 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
16783 getRenderer : function(col){
16784 if(!this.config[col].renderer){
16785 return Roo.grid.ColumnModel.defaultRenderer;
16787 return this.config[col].renderer;
16791 * Sets the rendering (formatting) function for a column.
16792 * @param {Number} col The column index
16793 * @param {Function} fn The function to use to process the cell's raw data
16794 * to return HTML markup for the grid view. The render function is called with
16795 * the following parameters:<ul>
16796 * <li>Data value.</li>
16797 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
16798 * <li>css A CSS style string to apply to the table cell.</li>
16799 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
16800 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
16801 * <li>Row index</li>
16802 * <li>Column index</li>
16803 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
16805 setRenderer : function(col, fn){
16806 this.config[col].renderer = fn;
16810 * Returns the width for the specified column.
16811 * @param {Number} col The column index
16814 getColumnWidth : function(col){
16815 return this.config[col].width * 1 || this.defaultWidth;
16819 * Sets the width for a column.
16820 * @param {Number} col The column index
16821 * @param {Number} width The new width
16823 setColumnWidth : function(col, width, suppressEvent){
16824 this.config[col].width = width;
16825 this.totalWidth = null;
16826 if(!suppressEvent){
16827 this.fireEvent("widthchange", this, col, width);
16832 * Returns the total width of all columns.
16833 * @param {Boolean} includeHidden True to include hidden column widths
16836 getTotalWidth : function(includeHidden){
16837 if(!this.totalWidth){
16838 this.totalWidth = 0;
16839 for(var i = 0, len = this.config.length; i < len; i++){
16840 if(includeHidden || !this.isHidden(i)){
16841 this.totalWidth += this.getColumnWidth(i);
16845 return this.totalWidth;
16849 * Returns the header for the specified column.
16850 * @param {Number} col The column index
16853 getColumnHeader : function(col){
16854 return this.config[col].header;
16858 * Sets the header for a column.
16859 * @param {Number} col The column index
16860 * @param {String} header The new header
16862 setColumnHeader : function(col, header){
16863 this.config[col].header = header;
16864 this.fireEvent("headerchange", this, col, header);
16868 * Returns the tooltip for the specified column.
16869 * @param {Number} col The column index
16872 getColumnTooltip : function(col){
16873 return this.config[col].tooltip;
16876 * Sets the tooltip for a column.
16877 * @param {Number} col The column index
16878 * @param {String} tooltip The new tooltip
16880 setColumnTooltip : function(col, tooltip){
16881 this.config[col].tooltip = tooltip;
16885 * Returns the dataIndex for the specified column.
16886 * @param {Number} col The column index
16889 getDataIndex : function(col){
16890 return this.config[col].dataIndex;
16894 * Sets the dataIndex for a column.
16895 * @param {Number} col The column index
16896 * @param {Number} dataIndex The new dataIndex
16898 setDataIndex : function(col, dataIndex){
16899 this.config[col].dataIndex = dataIndex;
16905 * Returns true if the cell is editable.
16906 * @param {Number} colIndex The column index
16907 * @param {Number} rowIndex The row index
16908 * @return {Boolean}
16910 isCellEditable : function(colIndex, rowIndex){
16911 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
16915 * Returns the editor defined for the cell/column.
16916 * return false or null to disable editing.
16917 * @param {Number} colIndex The column index
16918 * @param {Number} rowIndex The row index
16921 getCellEditor : function(colIndex, rowIndex){
16922 return this.config[colIndex].editor;
16926 * Sets if a column is editable.
16927 * @param {Number} col The column index
16928 * @param {Boolean} editable True if the column is editable
16930 setEditable : function(col, editable){
16931 this.config[col].editable = editable;
16936 * Returns true if the column is hidden.
16937 * @param {Number} colIndex The column index
16938 * @return {Boolean}
16940 isHidden : function(colIndex){
16941 return this.config[colIndex].hidden;
16946 * Returns true if the column width cannot be changed
16948 isFixed : function(colIndex){
16949 return this.config[colIndex].fixed;
16953 * Returns true if the column can be resized
16954 * @return {Boolean}
16956 isResizable : function(colIndex){
16957 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
16960 * Sets if a column is hidden.
16961 * @param {Number} colIndex The column index
16962 * @param {Boolean} hidden True if the column is hidden
16964 setHidden : function(colIndex, hidden){
16965 this.config[colIndex].hidden = hidden;
16966 this.totalWidth = null;
16967 this.fireEvent("hiddenchange", this, colIndex, hidden);
16971 * Sets the editor for a column.
16972 * @param {Number} col The column index
16973 * @param {Object} editor The editor object
16975 setEditor : function(col, editor){
16976 this.config[col].editor = editor;
16980 Roo.grid.ColumnModel.defaultRenderer = function(value){
16981 if(typeof value == "string" && value.length < 1){
16987 // Alias for backwards compatibility
16988 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
16991 * @class Roo.bootstrap.Table.AbstractSelectionModel
16992 * @extends Roo.util.Observable
16993 * Abstract base class for grid SelectionModels. It provides the interface that should be
16994 * implemented by descendant classes. This class should not be directly instantiated.
16997 Roo.bootstrap.Table.AbstractSelectionModel = function(){
16998 this.locked = false;
16999 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
17003 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
17004 /** @ignore Called by the grid automatically. Do not call directly. */
17005 init : function(grid){
17011 * Locks the selections.
17014 this.locked = true;
17018 * Unlocks the selections.
17020 unlock : function(){
17021 this.locked = false;
17025 * Returns true if the selections are locked.
17026 * @return {Boolean}
17028 isLocked : function(){
17029 return this.locked;
17033 * @extends Roo.bootstrap.Table.AbstractSelectionModel
17034 * @class Roo.bootstrap.Table.RowSelectionModel
17035 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
17036 * It supports multiple selections and keyboard selection/navigation.
17038 * @param {Object} config
17041 Roo.bootstrap.Table.RowSelectionModel = function(config){
17042 Roo.apply(this, config);
17043 this.selections = new Roo.util.MixedCollection(false, function(o){
17048 this.lastActive = false;
17052 * @event selectionchange
17053 * Fires when the selection changes
17054 * @param {SelectionModel} this
17056 "selectionchange" : true,
17058 * @event afterselectionchange
17059 * Fires after the selection changes (eg. by key press or clicking)
17060 * @param {SelectionModel} this
17062 "afterselectionchange" : true,
17064 * @event beforerowselect
17065 * Fires when a row is selected being selected, return false to cancel.
17066 * @param {SelectionModel} this
17067 * @param {Number} rowIndex The selected index
17068 * @param {Boolean} keepExisting False if other selections will be cleared
17070 "beforerowselect" : true,
17073 * Fires when a row is selected.
17074 * @param {SelectionModel} this
17075 * @param {Number} rowIndex The selected index
17076 * @param {Roo.data.Record} r The record
17078 "rowselect" : true,
17080 * @event rowdeselect
17081 * Fires when a row is deselected.
17082 * @param {SelectionModel} this
17083 * @param {Number} rowIndex The selected index
17085 "rowdeselect" : true
17087 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
17088 this.locked = false;
17091 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
17093 * @cfg {Boolean} singleSelect
17094 * True to allow selection of only one row at a time (defaults to false)
17096 singleSelect : false,
17099 initEvents : function(){
17101 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
17102 this.grid.on("mousedown", this.handleMouseDown, this);
17103 }else{ // allow click to work like normal
17104 this.grid.on("rowclick", this.handleDragableRowClick, this);
17107 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
17108 "up" : function(e){
17110 this.selectPrevious(e.shiftKey);
17111 }else if(this.last !== false && this.lastActive !== false){
17112 var last = this.last;
17113 this.selectRange(this.last, this.lastActive-1);
17114 this.grid.getView().focusRow(this.lastActive);
17115 if(last !== false){
17119 this.selectFirstRow();
17121 this.fireEvent("afterselectionchange", this);
17123 "down" : function(e){
17125 this.selectNext(e.shiftKey);
17126 }else if(this.last !== false && this.lastActive !== false){
17127 var last = this.last;
17128 this.selectRange(this.last, this.lastActive+1);
17129 this.grid.getView().focusRow(this.lastActive);
17130 if(last !== false){
17134 this.selectFirstRow();
17136 this.fireEvent("afterselectionchange", this);
17141 var view = this.grid.view;
17142 view.on("refresh", this.onRefresh, this);
17143 view.on("rowupdated", this.onRowUpdated, this);
17144 view.on("rowremoved", this.onRemove, this);
17148 onRefresh : function(){
17149 var ds = this.grid.dataSource, i, v = this.grid.view;
17150 var s = this.selections;
17151 s.each(function(r){
17152 if((i = ds.indexOfId(r.id)) != -1){
17161 onRemove : function(v, index, r){
17162 this.selections.remove(r);
17166 onRowUpdated : function(v, index, r){
17167 if(this.isSelected(r)){
17168 v.onRowSelect(index);
17174 * @param {Array} records The records to select
17175 * @param {Boolean} keepExisting (optional) True to keep existing selections
17177 selectRecords : function(records, keepExisting){
17179 this.clearSelections();
17181 var ds = this.grid.dataSource;
17182 for(var i = 0, len = records.length; i < len; i++){
17183 this.selectRow(ds.indexOf(records[i]), true);
17188 * Gets the number of selected rows.
17191 getCount : function(){
17192 return this.selections.length;
17196 * Selects the first row in the grid.
17198 selectFirstRow : function(){
17203 * Select the last row.
17204 * @param {Boolean} keepExisting (optional) True to keep existing selections
17206 selectLastRow : function(keepExisting){
17207 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
17211 * Selects the row immediately following the last selected row.
17212 * @param {Boolean} keepExisting (optional) True to keep existing selections
17214 selectNext : function(keepExisting){
17215 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
17216 this.selectRow(this.last+1, keepExisting);
17217 this.grid.getView().focusRow(this.last);
17222 * Selects the row that precedes the last selected row.
17223 * @param {Boolean} keepExisting (optional) True to keep existing selections
17225 selectPrevious : function(keepExisting){
17227 this.selectRow(this.last-1, keepExisting);
17228 this.grid.getView().focusRow(this.last);
17233 * Returns the selected records
17234 * @return {Array} Array of selected records
17236 getSelections : function(){
17237 return [].concat(this.selections.items);
17241 * Returns the first selected record.
17244 getSelected : function(){
17245 return this.selections.itemAt(0);
17250 * Clears all selections.
17252 clearSelections : function(fast){
17253 if(this.locked) return;
17255 var ds = this.grid.dataSource;
17256 var s = this.selections;
17257 s.each(function(r){
17258 this.deselectRow(ds.indexOfId(r.id));
17262 this.selections.clear();
17269 * Selects all rows.
17271 selectAll : function(){
17272 if(this.locked) return;
17273 this.selections.clear();
17274 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
17275 this.selectRow(i, true);
17280 * Returns True if there is a selection.
17281 * @return {Boolean}
17283 hasSelection : function(){
17284 return this.selections.length > 0;
17288 * Returns True if the specified row is selected.
17289 * @param {Number/Record} record The record or index of the record to check
17290 * @return {Boolean}
17292 isSelected : function(index){
17293 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
17294 return (r && this.selections.key(r.id) ? true : false);
17298 * Returns True if the specified record id is selected.
17299 * @param {String} id The id of record to check
17300 * @return {Boolean}
17302 isIdSelected : function(id){
17303 return (this.selections.key(id) ? true : false);
17307 handleMouseDown : function(e, t){
17308 var view = this.grid.getView(), rowIndex;
17309 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
17312 if(e.shiftKey && this.last !== false){
17313 var last = this.last;
17314 this.selectRange(last, rowIndex, e.ctrlKey);
17315 this.last = last; // reset the last
17316 view.focusRow(rowIndex);
17318 var isSelected = this.isSelected(rowIndex);
17319 if(e.button !== 0 && isSelected){
17320 view.focusRow(rowIndex);
17321 }else if(e.ctrlKey && isSelected){
17322 this.deselectRow(rowIndex);
17323 }else if(!isSelected){
17324 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
17325 view.focusRow(rowIndex);
17328 this.fireEvent("afterselectionchange", this);
17331 handleDragableRowClick : function(grid, rowIndex, e)
17333 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
17334 this.selectRow(rowIndex, false);
17335 grid.view.focusRow(rowIndex);
17336 this.fireEvent("afterselectionchange", this);
17341 * Selects multiple rows.
17342 * @param {Array} rows Array of the indexes of the row to select
17343 * @param {Boolean} keepExisting (optional) True to keep existing selections
17345 selectRows : function(rows, keepExisting){
17347 this.clearSelections();
17349 for(var i = 0, len = rows.length; i < len; i++){
17350 this.selectRow(rows[i], true);
17355 * Selects a range of rows. All rows in between startRow and endRow are also selected.
17356 * @param {Number} startRow The index of the first row in the range
17357 * @param {Number} endRow The index of the last row in the range
17358 * @param {Boolean} keepExisting (optional) True to retain existing selections
17360 selectRange : function(startRow, endRow, keepExisting){
17361 if(this.locked) return;
17363 this.clearSelections();
17365 if(startRow <= endRow){
17366 for(var i = startRow; i <= endRow; i++){
17367 this.selectRow(i, true);
17370 for(var i = startRow; i >= endRow; i--){
17371 this.selectRow(i, true);
17377 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
17378 * @param {Number} startRow The index of the first row in the range
17379 * @param {Number} endRow The index of the last row in the range
17381 deselectRange : function(startRow, endRow, preventViewNotify){
17382 if(this.locked) return;
17383 for(var i = startRow; i <= endRow; i++){
17384 this.deselectRow(i, preventViewNotify);
17390 * @param {Number} row The index of the row to select
17391 * @param {Boolean} keepExisting (optional) True to keep existing selections
17393 selectRow : function(index, keepExisting, preventViewNotify){
17394 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
17395 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
17396 if(!keepExisting || this.singleSelect){
17397 this.clearSelections();
17399 var r = this.grid.dataSource.getAt(index);
17400 this.selections.add(r);
17401 this.last = this.lastActive = index;
17402 if(!preventViewNotify){
17403 this.grid.getView().onRowSelect(index);
17405 this.fireEvent("rowselect", this, index, r);
17406 this.fireEvent("selectionchange", this);
17412 * @param {Number} row The index of the row to deselect
17414 deselectRow : function(index, preventViewNotify){
17415 if(this.locked) return;
17416 if(this.last == index){
17419 if(this.lastActive == index){
17420 this.lastActive = false;
17422 var r = this.grid.dataSource.getAt(index);
17423 this.selections.remove(r);
17424 if(!preventViewNotify){
17425 this.grid.getView().onRowDeselect(index);
17427 this.fireEvent("rowdeselect", this, index);
17428 this.fireEvent("selectionchange", this);
17432 restoreLast : function(){
17434 this.last = this._last;
17439 acceptsNav : function(row, col, cm){
17440 return !cm.isHidden(col) && cm.isCellEditable(col, row);
17444 onEditorKey : function(field, e){
17445 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
17450 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
17452 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
17454 }else if(k == e.ENTER && !e.ctrlKey){
17458 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
17460 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
17462 }else if(k == e.ESC){
17466 g.startEditing(newCell[0], newCell[1]);
17471 * Ext JS Library 1.1.1
17472 * Copyright(c) 2006-2007, Ext JS, LLC.
17474 * Originally Released Under LGPL - original licence link has changed is not relivant.
17477 * <script type="text/javascript">
17481 * @class Roo.bootstrap.PagingToolbar
17483 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
17485 * Create a new PagingToolbar
17486 * @param {Object} config The config object
17488 Roo.bootstrap.PagingToolbar = function(config)
17490 // old args format still supported... - xtype is prefered..
17491 // created from xtype...
17492 var ds = config.dataSource;
17494 if (config.items) {
17495 items = config.items;
17499 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
17506 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
17508 // supprot items array.
17510 Roo.each(items, function(e) {
17511 this.add(Roo.factory(e));
17520 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
17522 * @cfg {Roo.data.Store} dataSource
17523 * The underlying data store providing the paged data
17526 * @cfg {String/HTMLElement/Element} container
17527 * container The id or element that will contain the toolbar
17530 * @cfg {Boolean} displayInfo
17531 * True to display the displayMsg (defaults to false)
17534 * @cfg {Number} pageSize
17535 * The number of records to display per page (defaults to 20)
17539 * @cfg {String} displayMsg
17540 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
17542 displayMsg : 'Displaying {0} - {1} of {2}',
17544 * @cfg {String} emptyMsg
17545 * The message to display when no records are found (defaults to "No data to display")
17547 emptyMsg : 'No data to display',
17549 * Customizable piece of the default paging text (defaults to "Page")
17552 beforePageText : "Page",
17554 * Customizable piece of the default paging text (defaults to "of %0")
17557 afterPageText : "of {0}",
17559 * Customizable piece of the default paging text (defaults to "First Page")
17562 firstText : "First Page",
17564 * Customizable piece of the default paging text (defaults to "Previous Page")
17567 prevText : "Previous Page",
17569 * Customizable piece of the default paging text (defaults to "Next Page")
17572 nextText : "Next Page",
17574 * Customizable piece of the default paging text (defaults to "Last Page")
17577 lastText : "Last Page",
17579 * Customizable piece of the default paging text (defaults to "Refresh")
17582 refreshText : "Refresh",
17585 onRender : function(ct, position)
17587 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
17588 this.navgroup.parentId = this.id;
17589 this.navgroup.onRender(this.el, null);
17590 // add the buttons to the navgroup
17592 this.first = this.navgroup.addItem({
17593 tooltip: this.firstText,
17595 icon : 'fa fa-backward',
17597 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
17600 this.prev = this.navgroup.addItem({
17601 tooltip: this.prevText,
17603 icon : 'fa fa-step-backward',
17605 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
17607 //this.addSeparator();
17610 var field = this.navgroup.addItem( {
17612 cls : 'x-paging-position',
17614 html : this.beforePageText +
17615 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
17616 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
17619 this.field = field.el.select('input', true).first();
17620 this.field.on("keydown", this.onPagingKeydown, this);
17621 this.field.on("focus", function(){this.dom.select();});
17624 this.afterTextEl = field.el.select('.x-paging-after').first();
17625 //this.field.setHeight(18);
17626 //this.addSeparator();
17627 this.next = this.navgroup.addItem({
17628 tooltip: this.nextText,
17630 html : ' <i class="fa fa-step-forward">',
17632 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
17634 this.last = this.navgroup.addItem({
17635 tooltip: this.lastText,
17636 icon : 'fa fa-forward',
17639 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
17641 //this.addSeparator();
17642 this.loading = this.navgroup.addItem({
17643 tooltip: this.refreshText,
17644 icon: 'fa fa-refresh',
17646 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
17649 if(this.displayInfo){
17650 var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info' } );
17651 this.displayEl = navel.el.select('a',true).first();
17657 updateInfo : function(){
17658 if(this.displayEl){
17659 var count = this.ds.getCount();
17660 var msg = count == 0 ?
17664 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
17666 this.displayEl.update(msg);
17671 onLoad : function(ds, r, o){
17672 this.cursor = o.params ? o.params.start : 0;
17673 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
17675 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
17676 this.field.dom.value = ap;
17677 this.first.setDisabled(ap == 1);
17678 this.prev.setDisabled(ap == 1);
17679 this.next.setDisabled(ap == ps);
17680 this.last.setDisabled(ap == ps);
17681 this.loading.enable();
17686 getPageData : function(){
17687 var total = this.ds.getTotalCount();
17690 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
17691 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
17696 onLoadError : function(){
17697 this.loading.enable();
17701 onPagingKeydown : function(e){
17702 var k = e.getKey();
17703 var d = this.getPageData();
17705 var v = this.field.dom.value, pageNum;
17706 if(!v || isNaN(pageNum = parseInt(v, 10))){
17707 this.field.dom.value = d.activePage;
17710 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
17711 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
17714 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))
17716 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
17717 this.field.dom.value = pageNum;
17718 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
17721 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
17723 var v = this.field.dom.value, pageNum;
17724 var increment = (e.shiftKey) ? 10 : 1;
17725 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
17727 if(!v || isNaN(pageNum = parseInt(v, 10))) {
17728 this.field.dom.value = d.activePage;
17731 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
17733 this.field.dom.value = parseInt(v, 10) + increment;
17734 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
17735 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
17742 beforeLoad : function(){
17744 this.loading.disable();
17749 onClick : function(which){
17756 ds.load({params:{start: 0, limit: this.pageSize}});
17759 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
17762 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
17765 var total = ds.getTotalCount();
17766 var extra = total % this.pageSize;
17767 var lastStart = extra ? (total - extra) : total-this.pageSize;
17768 ds.load({params:{start: lastStart, limit: this.pageSize}});
17771 ds.load({params:{start: this.cursor, limit: this.pageSize}});
17777 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
17778 * @param {Roo.data.Store} store The data store to unbind
17780 unbind : function(ds){
17781 ds.un("beforeload", this.beforeLoad, this);
17782 ds.un("load", this.onLoad, this);
17783 ds.un("loadexception", this.onLoadError, this);
17784 ds.un("remove", this.updateInfo, this);
17785 ds.un("add", this.updateInfo, this);
17786 this.ds = undefined;
17790 * Binds the paging toolbar to the specified {@link Roo.data.Store}
17791 * @param {Roo.data.Store} store The data store to bind
17793 bind : function(ds){
17794 ds.on("beforeload", this.beforeLoad, this);
17795 ds.on("load", this.onLoad, this);
17796 ds.on("loadexception", this.onLoadError, this);
17797 ds.on("remove", this.updateInfo, this);
17798 ds.on("add", this.updateInfo, this);
17809 * @class Roo.bootstrap.MessageBar
17810 * @extends Roo.bootstrap.Component
17811 * Bootstrap MessageBar class
17812 * @cfg {String} html contents of the MessageBar
17813 * @cfg {String} weight (info | success | warning | danger) default info
17814 * @cfg {String} beforeClass insert the bar before the given class
17815 * @cfg {Boolean} closable (true | false) default false
17816 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
17819 * Create a new Element
17820 * @param {Object} config The config object
17823 Roo.bootstrap.MessageBar = function(config){
17824 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
17827 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
17833 beforeClass: 'bootstrap-sticky-wrap',
17835 getAutoCreate : function(){
17839 cls: 'alert alert-dismissable alert-' + this.weight,
17844 html: this.html || ''
17850 cfg.cls += ' alert-messages-fixed';
17864 onRender : function(ct, position)
17866 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17869 var cfg = Roo.apply({}, this.getAutoCreate());
17873 cfg.cls += ' ' + this.cls;
17876 cfg.style = this.style;
17878 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
17880 this.el.setVisibilityMode(Roo.Element.DISPLAY);
17883 this.el.select('>button.close').on('click', this.hide, this);
17889 if (!this.rendered) {
17895 this.fireEvent('show', this);
17901 if (!this.rendered) {
17907 this.fireEvent('hide', this);
17910 update : function()
17912 // var e = this.el.dom.firstChild;
17914 // if(this.closable){
17915 // e = e.nextSibling;
17918 // e.data = this.html || '';
17920 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';