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]());
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]());
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]());
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();
2844 * @class Roo.bootstrap.NavSimplebar
2845 * @extends Roo.bootstrap.Navbar
2846 * Bootstrap Sidebar class
2848 * @cfg {Boolean} inverse is inverted color
2850 * @cfg {String} type (nav | pills | tabs)
2851 * @cfg {Boolean} arrangement stacked | justified
2852 * @cfg {String} align (left | right) alignment
2854 * @cfg {Boolean} main (true|false) main nav bar? default false
2855 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
2857 * @cfg {String} tag (header|footer|nav|div) default is nav
2863 * Create a new Sidebar
2864 * @param {Object} config The config object
2868 Roo.bootstrap.NavSimplebar = function(config){
2869 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
2872 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
2888 getAutoCreate : function(){
2892 tag : this.tag || 'div',
2905 this.type = this.type || 'nav';
2906 if (['tabs','pills'].indexOf(this.type)!==-1) {
2907 cfg.cn[0].cls += ' nav-' + this.type
2911 if (this.type!=='nav') {
2912 Roo.log('nav type must be nav/tabs/pills')
2914 cfg.cn[0].cls += ' navbar-nav'
2920 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
2921 cfg.cn[0].cls += ' nav-' + this.arrangement;
2925 if (this.align === 'right') {
2926 cfg.cn[0].cls += ' navbar-right';
2930 cfg.cls += ' navbar-inverse';
2957 * @class Roo.bootstrap.NavHeaderbar
2958 * @extends Roo.bootstrap.NavSimplebar
2959 * Bootstrap Sidebar class
2961 * @cfg {String} brand what is brand
2962 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
2963 * @cfg {String} brand_href href of the brand
2966 * Create a new Sidebar
2967 * @param {Object} config The config object
2971 Roo.bootstrap.NavHeaderbar = function(config){
2972 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
2975 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
2982 getAutoCreate : function(){
2987 tag: this.nav || 'nav',
2993 cls: 'navbar-header',
2998 cls: 'navbar-toggle',
2999 'data-toggle': 'collapse',
3004 html: 'Toggle navigation'
3024 cls: 'collapse navbar-collapse'
3029 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3031 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3032 cfg.cls += ' navbar-' + this.position;
3034 // tag can override this..
3036 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3039 if (this.brand !== '') {
3042 href: this.brand_href ? this.brand_href : '#',
3043 cls: 'navbar-brand',
3051 cfg.cls += ' main-nav';
3076 * @class Roo.bootstrap.NavSidebar
3077 * @extends Roo.bootstrap.Navbar
3078 * Bootstrap Sidebar class
3081 * Create a new Sidebar
3082 * @param {Object} config The config object
3086 Roo.bootstrap.NavSidebar = function(config){
3087 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3090 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3092 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3094 getAutoCreate : function(){
3099 cls: 'sidebar sidebar-nav'
3121 * @class Roo.bootstrap.NavGroup
3122 * @extends Roo.bootstrap.Component
3123 * Bootstrap NavGroup class
3124 * @cfg {String} align left | right
3125 * @cfg {Boolean} inverse false | true
3126 * @cfg {String} type (nav|pills|tab) default nav
3127 * @cfg {String} navId - reference Id for navbar.
3131 * Create a new nav group
3132 * @param {Object} config The config object
3135 Roo.bootstrap.NavGroup = function(config){
3136 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3138 Roo.bootstrap.NavGroup.register(this);
3142 * Fires when the active item changes
3143 * @param {Roo.bootstrap.NavGroup} this
3144 * @param {Roo.bootstrap.Navbar.Item} item The item selected
3145 * @param {Roo.bootstrap.Navbar.Item} item The previously selected item
3152 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3163 getAutoCreate : function()
3165 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3172 if (['tabs','pills'].indexOf(this.type)!==-1) {
3173 cfg.cls += ' nav-' + this.type
3175 if (this.type!=='nav') {
3176 Roo.log('nav type must be nav/tabs/pills')
3178 cfg.cls += ' navbar-nav'
3181 if (this.parent().sidebar) {
3184 cls: 'dashboard-menu sidebar-menu'
3190 if (this.form === true) {
3196 if (this.align === 'right') {
3197 cfg.cls += ' navbar-right';
3199 cfg.cls += ' navbar-left';
3203 if (this.align === 'right') {
3204 cfg.cls += ' navbar-right';
3208 cfg.cls += ' navbar-inverse';
3216 setActiveItem : function(item)
3219 Roo.each(this.navItems, function(v){
3224 v.setActive(false, true);
3231 item.setActive(true, true);
3232 this.fireEvent('changed', this, item, prev);
3238 register : function(item)
3240 this.navItems.push( item);
3241 item.navId = this.navId;
3244 getNavItem: function(tabId)
3247 Roo.each(this.navItems, function(e) {
3248 if (e.tabId == tabId) {
3260 Roo.apply(Roo.bootstrap.NavGroup, {
3264 register : function(navgrp)
3266 this.groups[navgrp.navId] = navgrp;
3269 get: function(navId) {
3270 return this.groups[navId];
3285 * @class Roo.bootstrap.Navbar.Item
3286 * @extends Roo.bootstrap.Component
3287 * Bootstrap Navbar.Button class
3288 * @cfg {String} href link to
3289 * @cfg {String} html content of button
3290 * @cfg {String} badge text inside badge
3291 * @cfg {String} glyphicon name of glyphicon
3292 * @cfg {String} icon name of font awesome icon
3293 * @cfg {Boolean} active Is item active
3294 * @cfg {Boolean} preventDefault (true | false) default false
3295 * @cfg {String} tabId the tab that this item activates.
3298 * Create a new Navbar Button
3299 * @param {Object} config The config object
3301 Roo.bootstrap.Navbar.Item = function(config){
3302 Roo.bootstrap.Navbar.Item.superclass.constructor.call(this, config);
3307 * The raw click event for the entire grid.
3308 * @param {Roo.EventObject} e
3313 * Fires when the active item active state changes
3314 * @param {Roo.bootstrap.Navbar.Item} this
3315 * @param {boolean} state the new state
3323 Roo.extend(Roo.bootstrap.Navbar.Item, Roo.bootstrap.Component, {
3331 preventDefault : false,
3334 getAutoCreate : function(){
3336 var cfg = Roo.apply({}, Roo.bootstrap.Navbar.Item.superclass.getAutoCreate.call(this));
3338 if (this.parent().parent().sidebar === true) {
3351 cfg.cn[0].html = this.html;
3355 this.cls += ' active';
3359 cfg.cn[0].cls += ' dropdown-toggle';
3360 cfg.cn[0].html = (cfg.cn[0].html || this.html) + '<span class="glyphicon glyphicon-chevron-down"></span>';
3364 cfg.cn[0].tag = 'a',
3365 cfg.cn[0].href = this.href;
3368 if (this.glyphicon) {
3369 cfg.cn[0].html = '<i class="glyphicon glyphicon-'+this.glyphicon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
3373 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
3385 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3395 if (this.glyphicon) {
3396 if(cfg.html){cfg.html = ' ' + this.html};
3400 cls: 'glyphicon glyphicon-' + this.glyphicon
3405 cfg.cn[0].html = this.html || cfg.cn[0].html ;
3410 cfg.cn[0].html += " <span class='caret'></span>";
3411 //}else if (!this.href) {
3412 // cfg.cn[0].tag='p';
3413 // cfg.cn[0].cls='navbar-text';
3416 cfg.cn[0].href=this.href||'#';
3417 cfg.cn[0].html=this.html;
3420 if (this.badge !== '') {
3423 cfg.cn[0].html + ' ',
3434 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
3439 initEvents: function() {
3440 // Roo.log('init events?');
3441 // Roo.log(this.el.dom);
3442 this.el.select('a',true).on('click', this.onClick, this);
3443 // at this point parent should be available..
3444 this.parent().register(this);
3447 onClick : function(e)
3449 if(this.preventDefault){
3453 if (typeof (this.menu) != 'undefined') {
3454 this.menu.parentType = this.xtype;
3455 this.menu.triggerEl = this.el;
3456 this.addxtype(Roo.apply({}, this.menu));
3459 if(this.fireEvent('click', this, e) === false){
3463 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3464 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3465 this.parent().setActiveItem(this);
3471 isActive: function () {
3474 setActive : function(state, fire)
3476 this.active = state;
3478 this.el.removeClass('active');
3479 } else if (!this.el.hasClass('active')) {
3480 this.el.addClass('active');
3483 this.fireEvent('changed', this, state);
3488 // this should not be here...
3501 * @class Roo.bootstrap.NavItem
3502 * @extends Roo.bootstrap.Component
3503 * Bootstrap Navbar.NavItem class
3504 * @cfg {String} href link to
3505 * @cfg {String} html content of button
3506 * @cfg {String} badge text inside badge
3507 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3508 * @cfg {String} glyphicon name of glyphicon
3509 * @cfg {String} icon name of font awesome icon
3510 * @cfg {Boolean} active Is item active
3511 * @cfg {Boolean} preventDefault (true | false) default false
3512 * @cfg {String} tabId the tab that this item activates.
3515 * Create a new Navbar Item
3516 * @param {Object} config The config object
3518 Roo.bootstrap.NavItem = function(config){
3519 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3524 * The raw click event for the entire grid.
3525 * @param {Roo.EventObject} e
3530 * Fires when the active item active state changes
3531 * @param {Roo.bootstrap.NavItem} this
3532 * @param {boolean} state the new state
3540 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3548 preventDefault : false,
3551 getAutoCreate : function(){
3559 href : this.href || "#",
3560 html: this.html || ''
3566 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3569 // glyphicon and icon go before content..
3570 if (this.glyphicon || this.icon) {
3572 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html + '</span>'
3574 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span>' + cfg.cn[0].html;
3582 cfg.cn[0].html += " <span class='caret'></span>";
3586 if (this.badge !== '') {
3588 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3595 initEvents: function() {
3596 // Roo.log('init events?');
3597 // Roo.log(this.el.dom);
3598 if (typeof (this.menu) != 'undefined') {
3599 this.menu.parentType = this.xtype;
3600 this.menu.triggerEl = this.el;
3601 this.addxtype(Roo.apply({}, this.menu));
3605 this.el.select('a',true).on('click', this.onClick, this);
3606 // at this point parent should be available..
3607 this.parent().register(this);
3610 onClick : function(e)
3612 if(this.preventDefault){
3616 if(this.fireEvent('click', this, e) === false){
3620 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3621 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3622 this.parent().setActiveItem(this);
3630 isActive: function () {
3633 setActive : function(state, fire)
3635 this.active = state;
3637 this.el.removeClass('active');
3638 } else if (!this.el.hasClass('active')) {
3639 this.el.addClass('active');
3642 this.fireEvent('changed', this, state);
3647 // this should not be here...
3658 * <span> icon </span>
3659 * <span> text </span>
3660 * <span>badge </span>
3664 * @class Roo.bootstrap.NavSidebarItem
3665 * @extends Roo.bootstrap.NavItem
3666 * Bootstrap Navbar.NavSidebarItem class
3668 * Create a new Navbar Button
3669 * @param {Object} config The config object
3671 Roo.bootstrap.NavSidebarItem = function(config){
3672 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3677 * The raw click event for the entire grid.
3678 * @param {Roo.EventObject} e
3683 * Fires when the active item active state changes
3684 * @param {Roo.bootstrap.NavSidebarItem} this
3685 * @param {boolean} state the new state
3693 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3696 getAutoCreate : function(){
3701 href : this.href || '#',
3713 html : this.html || ''
3718 cfg.cls += ' active';
3722 if (this.glyphicon || this.icon) {
3723 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3724 a.cn.push({ tag : 'i', cls : c }) ;
3729 if (this.badge !== '') {
3730 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3734 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3735 a.cls += 'dropdown-toggle treeview' ;
3759 * @class Roo.bootstrap.Row
3760 * @extends Roo.bootstrap.Component
3761 * Bootstrap Row class (contains columns...)
3765 * @param {Object} config The config object
3768 Roo.bootstrap.Row = function(config){
3769 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3772 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3774 getAutoCreate : function(){
3793 * @class Roo.bootstrap.Element
3794 * @extends Roo.bootstrap.Component
3795 * Bootstrap Element class
3796 * @cfg {String} html contents of the element
3797 * @cfg {String} tag tag of the element
3798 * @cfg {String} cls class of the element
3801 * Create a new Element
3802 * @param {Object} config The config object
3805 Roo.bootstrap.Element = function(config){
3806 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3809 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3816 getAutoCreate : function(){
3841 * @class Roo.bootstrap.Pagination
3842 * @extends Roo.bootstrap.Component
3843 * Bootstrap Pagination class
3844 * @cfg {String} size xs | sm | md | lg
3845 * @cfg {Boolean} inverse false | true
3848 * Create a new Pagination
3849 * @param {Object} config The config object
3852 Roo.bootstrap.Pagination = function(config){
3853 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3856 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3862 getAutoCreate : function(){
3868 cfg.cls += ' inverse';
3874 cfg.cls += " " + this.cls;
3892 * @class Roo.bootstrap.PaginationItem
3893 * @extends Roo.bootstrap.Component
3894 * Bootstrap PaginationItem class
3895 * @cfg {String} html text
3896 * @cfg {String} href the link
3897 * @cfg {Boolean} preventDefault (true | false) default true
3898 * @cfg {Boolean} active (true | false) default false
3902 * Create a new PaginationItem
3903 * @param {Object} config The config object
3907 Roo.bootstrap.PaginationItem = function(config){
3908 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3913 * The raw click event for the entire grid.
3914 * @param {Roo.EventObject} e
3920 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
3924 preventDefault: true,
3928 getAutoCreate : function(){
3934 href : this.href ? this.href : '#',
3935 html : this.html ? this.html : ''
3945 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
3951 initEvents: function() {
3953 this.el.on('click', this.onClick, this);
3956 onClick : function(e)
3958 Roo.log('PaginationItem on click ');
3959 if(this.preventDefault){
3963 this.fireEvent('click', this, e);
3979 * @class Roo.bootstrap.Slider
3980 * @extends Roo.bootstrap.Component
3981 * Bootstrap Slider class
3984 * Create a new Slider
3985 * @param {Object} config The config object
3988 Roo.bootstrap.Slider = function(config){
3989 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
3992 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
3994 getAutoCreate : function(){
3998 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4002 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4020 * @class Roo.bootstrap.Table
4021 * @extends Roo.bootstrap.Component
4022 * Bootstrap Table class
4023 * @cfg {String} cls table class
4024 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4025 * @cfg {String} bgcolor Specifies the background color for a table
4026 * @cfg {Number} border Specifies whether the table cells should have borders or not
4027 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4028 * @cfg {Number} cellspacing Specifies the space between cells
4029 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4030 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4031 * @cfg {String} sortable Specifies that the table should be sortable
4032 * @cfg {String} summary Specifies a summary of the content of a table
4033 * @cfg {Number} width Specifies the width of a table
4035 * @cfg {boolean} striped Should the rows be alternative striped
4036 * @cfg {boolean} bordered Add borders to the table
4037 * @cfg {boolean} hover Add hover highlighting
4038 * @cfg {boolean} condensed Format condensed
4039 * @cfg {boolean} responsive Format condensed
4040 * @cfg {Boolean} loadMask (true|false) default false
4046 * Create a new Table
4047 * @param {Object} config The config object
4050 Roo.bootstrap.Table = function(config){
4051 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4054 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4055 this.sm = this.selModel;
4056 this.sm.xmodule = this.xmodule || false;
4058 if (this.cm && typeof(this.cm.config) == 'undefined') {
4059 this.colModel = new Roo.bootstrap.Table.ColumnModel(this.cm);
4060 this.cm = this.colModel;
4061 this.cm.xmodule = this.xmodule || false;
4064 this.store= Roo.factory(this.store, Roo.data);
4065 this.ds = this.store;
4066 this.ds.xmodule = this.xmodule || false;
4071 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4094 getAutoCreate : function(){
4095 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4104 cfg.cls += ' table-striped';
4107 cfg.cls += ' table-hover';
4109 if (this.bordered) {
4110 cfg.cls += ' table-bordered';
4112 if (this.condensed) {
4113 cfg.cls += ' table-condensed';
4115 if (this.responsive) {
4116 cfg.cls += ' table-responsive';
4123 cfg.cls+= ' ' +this.cls;
4126 // this lot should be simplifed...
4129 cfg.align=this.align;
4132 cfg.bgcolor=this.bgcolor;
4135 cfg.border=this.border;
4137 if (this.cellpadding) {
4138 cfg.cellpadding=this.cellpadding;
4140 if (this.cellspacing) {
4141 cfg.cellspacing=this.cellspacing;
4144 cfg.frame=this.frame;
4147 cfg.rules=this.rules;
4149 if (this.sortable) {
4150 cfg.sortable=this.sortable;
4153 cfg.summary=this.summary;
4156 cfg.width=this.width;
4159 if(this.store || this.cm){
4160 cfg.cn.push(this.renderHeader());
4161 cfg.cn.push(this.renderBody());
4162 cfg.cn.push(this.renderFooter());
4164 cfg.cls+= ' TableGrid';
4170 // initTableGrid : function()
4179 // var cm = this.cm;
4181 // for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4184 // html: cm.getColumnHeader(i)
4188 // cfg.push(header);
4195 initEvents : function()
4197 if(!this.store || !this.cm){
4201 Roo.log('initEvents with ds!!!!');
4205 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4206 e.on('click', _this.sort, _this);
4208 // this.maskEl = Roo.DomHelper.append(this.el.select('.TableGrid', true).first(), {tag: "div", cls:"x-dlg-mask"}, true);
4209 // this.maskEl.enableDisplayMode("block");
4210 // this.maskEl.show();
4212 this.parent().el.setStyle('position', 'relative');
4217 style: "text-align:center",
4221 style: "background-color:white;width:50%;margin:100 auto",
4225 src: rootURL + '/roojs1/images/ux/lightbox/loading.gif'
4236 this.maskEl = Roo.DomHelper.append(this.parent().el, mark, true);
4238 var size = this.parent().el.getSize();
4240 this.maskEl.setSize(size.width, 300); // we will fix the height at the beginning...
4242 this.maskEl.enableDisplayMode("block");
4244 this.store.on('load', this.onLoad, this);
4245 this.store.on('beforeload', this.onBeforeLoad, this);
4253 sort : function(e,el)
4255 var col = Roo.get(el)
4257 if(!col.hasClass('sortable')){
4261 var sort = col.attr('sort');
4264 if(col.hasClass('glyphicon-arrow-up')){
4268 this.store.sortInfo = {field : sort, direction : dir};
4273 renderHeader : function()
4282 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4284 var config = cm.config[i];
4288 html: cm.getColumnHeader(i)
4291 if(typeof(config.dataIndex) != 'undefined'){
4292 c.sort = config.dataIndex;
4295 if(typeof(config.sortable) != 'undefined' && config.sortable){
4299 if(typeof(config.width) != 'undefined'){
4300 c.style = 'width:' + config.width + 'px';
4309 renderBody : function()
4319 renderFooter : function()
4331 Roo.log('ds onload');
4336 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4337 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
4339 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
4340 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
4343 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
4344 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
4348 var tbody = this.el.select('tbody', true).first();
4352 if(this.store.getCount() > 0){
4353 this.store.data.each(function(d){
4359 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4360 var renderer = cm.getRenderer(i);
4361 var config = cm.config[i];
4365 if(typeof(renderer) !== 'undefined'){
4366 value = renderer(d.data[cm.getDataIndex(i)], false, d);
4369 if(typeof(value) === 'object'){
4379 html: (typeof(value) === 'object') ? '' : value
4382 if(typeof(config.width) != 'undefined'){
4383 td.style = 'width:' + config.width + 'px';
4390 tbody.createChild(row);
4398 Roo.each(renders, function(r){
4399 _this.renderColumn(r);
4408 onBeforeLoad : function()
4410 Roo.log('ds onBeforeLoad');
4421 this.el.select('tbody', true).first().dom.innerHTML = '';
4424 getSelectionModel : function(){
4426 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
4428 return this.selModel;
4431 renderColumn : function(r)
4434 r.cfg.render(Roo.get(r.id));
4437 Roo.each(r.cfg.cn, function(c){
4442 _this.renderColumn(child);
4459 * @class Roo.bootstrap.TableCell
4460 * @extends Roo.bootstrap.Component
4461 * Bootstrap TableCell class
4462 * @cfg {String} html cell contain text
4463 * @cfg {String} cls cell class
4464 * @cfg {String} tag cell tag (td|th) default td
4465 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
4466 * @cfg {String} align Aligns the content in a cell
4467 * @cfg {String} axis Categorizes cells
4468 * @cfg {String} bgcolor Specifies the background color of a cell
4469 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
4470 * @cfg {Number} colspan Specifies the number of columns a cell should span
4471 * @cfg {String} headers Specifies one or more header cells a cell is related to
4472 * @cfg {Number} height Sets the height of a cell
4473 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
4474 * @cfg {Number} rowspan Sets the number of rows a cell should span
4475 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
4476 * @cfg {String} valign Vertical aligns the content in a cell
4477 * @cfg {Number} width Specifies the width of a cell
4480 * Create a new TableCell
4481 * @param {Object} config The config object
4484 Roo.bootstrap.TableCell = function(config){
4485 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
4488 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
4508 getAutoCreate : function(){
4509 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
4529 cfg.align=this.align
4535 cfg.bgcolor=this.bgcolor
4538 cfg.charoff=this.charoff
4541 cfg.colspan=this.colspan
4544 cfg.headers=this.headers
4547 cfg.height=this.height
4550 cfg.nowrap=this.nowrap
4553 cfg.rowspan=this.rowspan
4556 cfg.scope=this.scope
4559 cfg.valign=this.valign
4562 cfg.width=this.width
4581 * @class Roo.bootstrap.TableRow
4582 * @extends Roo.bootstrap.Component
4583 * Bootstrap TableRow class
4584 * @cfg {String} cls row class
4585 * @cfg {String} align Aligns the content in a table row
4586 * @cfg {String} bgcolor Specifies a background color for a table row
4587 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
4588 * @cfg {String} valign Vertical aligns the content in a table row
4591 * Create a new TableRow
4592 * @param {Object} config The config object
4595 Roo.bootstrap.TableRow = function(config){
4596 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
4599 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
4607 getAutoCreate : function(){
4608 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
4618 cfg.align = this.align;
4621 cfg.bgcolor = this.bgcolor;
4624 cfg.charoff = this.charoff;
4627 cfg.valign = this.valign;
4645 * @class Roo.bootstrap.TableBody
4646 * @extends Roo.bootstrap.Component
4647 * Bootstrap TableBody class
4648 * @cfg {String} cls element class
4649 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
4650 * @cfg {String} align Aligns the content inside the element
4651 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
4652 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
4655 * Create a new TableBody
4656 * @param {Object} config The config object
4659 Roo.bootstrap.TableBody = function(config){
4660 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
4663 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
4671 getAutoCreate : function(){
4672 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
4686 cfg.align = this.align;
4689 cfg.charoff = this.charoff;
4692 cfg.valign = this.valign;
4699 // initEvents : function()
4706 // this.store = Roo.factory(this.store, Roo.data);
4707 // this.store.on('load', this.onLoad, this);
4709 // this.store.load();
4713 // onLoad: function ()
4715 // this.fireEvent('load', this);
4725 * Ext JS Library 1.1.1
4726 * Copyright(c) 2006-2007, Ext JS, LLC.
4728 * Originally Released Under LGPL - original licence link has changed is not relivant.
4731 * <script type="text/javascript">
4734 // as we use this in bootstrap.
4735 Roo.namespace('Roo.form');
4737 * @class Roo.form.Action
4738 * Internal Class used to handle form actions
4740 * @param {Roo.form.BasicForm} el The form element or its id
4741 * @param {Object} config Configuration options
4746 // define the action interface
4747 Roo.form.Action = function(form, options){
4749 this.options = options || {};
4752 * Client Validation Failed
4755 Roo.form.Action.CLIENT_INVALID = 'client';
4757 * Server Validation Failed
4760 Roo.form.Action.SERVER_INVALID = 'server';
4762 * Connect to Server Failed
4765 Roo.form.Action.CONNECT_FAILURE = 'connect';
4767 * Reading Data from Server Failed
4770 Roo.form.Action.LOAD_FAILURE = 'load';
4772 Roo.form.Action.prototype = {
4774 failureType : undefined,
4775 response : undefined,
4779 run : function(options){
4784 success : function(response){
4789 handleResponse : function(response){
4793 // default connection failure
4794 failure : function(response){
4796 this.response = response;
4797 this.failureType = Roo.form.Action.CONNECT_FAILURE;
4798 this.form.afterAction(this, false);
4801 processResponse : function(response){
4802 this.response = response;
4803 if(!response.responseText){
4806 this.result = this.handleResponse(response);
4810 // utility functions used internally
4811 getUrl : function(appendParams){
4812 var url = this.options.url || this.form.url || this.form.el.dom.action;
4814 var p = this.getParams();
4816 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
4822 getMethod : function(){
4823 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
4826 getParams : function(){
4827 var bp = this.form.baseParams;
4828 var p = this.options.params;
4830 if(typeof p == "object"){
4831 p = Roo.urlEncode(Roo.applyIf(p, bp));
4832 }else if(typeof p == 'string' && bp){
4833 p += '&' + Roo.urlEncode(bp);
4836 p = Roo.urlEncode(bp);
4841 createCallback : function(){
4843 success: this.success,
4844 failure: this.failure,
4846 timeout: (this.form.timeout*1000),
4847 upload: this.form.fileUpload ? this.success : undefined
4852 Roo.form.Action.Submit = function(form, options){
4853 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
4856 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
4859 haveProgress : false,
4860 uploadComplete : false,
4862 // uploadProgress indicator.
4863 uploadProgress : function()
4865 if (!this.form.progressUrl) {
4869 if (!this.haveProgress) {
4870 Roo.MessageBox.progress("Uploading", "Uploading");
4872 if (this.uploadComplete) {
4873 Roo.MessageBox.hide();
4877 this.haveProgress = true;
4879 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
4881 var c = new Roo.data.Connection();
4883 url : this.form.progressUrl,
4888 success : function(req){
4889 //console.log(data);
4893 rdata = Roo.decode(req.responseText)
4895 Roo.log("Invalid data from server..");
4899 if (!rdata || !rdata.success) {
4901 Roo.MessageBox.alert(Roo.encode(rdata));
4904 var data = rdata.data;
4906 if (this.uploadComplete) {
4907 Roo.MessageBox.hide();
4912 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
4913 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
4916 this.uploadProgress.defer(2000,this);
4919 failure: function(data) {
4920 Roo.log('progress url failed ');
4931 // run get Values on the form, so it syncs any secondary forms.
4932 this.form.getValues();
4934 var o = this.options;
4935 var method = this.getMethod();
4936 var isPost = method == 'POST';
4937 if(o.clientValidation === false || this.form.isValid()){
4939 if (this.form.progressUrl) {
4940 this.form.findField('UPLOAD_IDENTIFIER').setValue(
4941 (new Date() * 1) + '' + Math.random());
4946 Roo.Ajax.request(Roo.apply(this.createCallback(), {
4947 form:this.form.el.dom,
4948 url:this.getUrl(!isPost),
4950 params:isPost ? this.getParams() : null,
4951 isUpload: this.form.fileUpload
4954 this.uploadProgress();
4956 }else if (o.clientValidation !== false){ // client validation failed
4957 this.failureType = Roo.form.Action.CLIENT_INVALID;
4958 this.form.afterAction(this, false);
4962 success : function(response)
4964 this.uploadComplete= true;
4965 if (this.haveProgress) {
4966 Roo.MessageBox.hide();
4970 var result = this.processResponse(response);
4971 if(result === true || result.success){
4972 this.form.afterAction(this, true);
4976 this.form.markInvalid(result.errors);
4977 this.failureType = Roo.form.Action.SERVER_INVALID;
4979 this.form.afterAction(this, false);
4981 failure : function(response)
4983 this.uploadComplete= true;
4984 if (this.haveProgress) {
4985 Roo.MessageBox.hide();
4988 this.response = response;
4989 this.failureType = Roo.form.Action.CONNECT_FAILURE;
4990 this.form.afterAction(this, false);
4993 handleResponse : function(response){
4994 if(this.form.errorReader){
4995 var rs = this.form.errorReader.read(response);
4998 for(var i = 0, len = rs.records.length; i < len; i++) {
4999 var r = rs.records[i];
5003 if(errors.length < 1){
5007 success : rs.success,
5013 ret = Roo.decode(response.responseText);
5017 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
5027 Roo.form.Action.Load = function(form, options){
5028 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
5029 this.reader = this.form.reader;
5032 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
5037 Roo.Ajax.request(Roo.apply(
5038 this.createCallback(), {
5039 method:this.getMethod(),
5040 url:this.getUrl(false),
5041 params:this.getParams()
5045 success : function(response){
5047 var result = this.processResponse(response);
5048 if(result === true || !result.success || !result.data){
5049 this.failureType = Roo.form.Action.LOAD_FAILURE;
5050 this.form.afterAction(this, false);
5053 this.form.clearInvalid();
5054 this.form.setValues(result.data);
5055 this.form.afterAction(this, true);
5058 handleResponse : function(response){
5059 if(this.form.reader){
5060 var rs = this.form.reader.read(response);
5061 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
5063 success : rs.success,
5067 return Roo.decode(response.responseText);
5071 Roo.form.Action.ACTION_TYPES = {
5072 'load' : Roo.form.Action.Load,
5073 'submit' : Roo.form.Action.Submit
5082 * @class Roo.bootstrap.Form
5083 * @extends Roo.bootstrap.Component
5084 * Bootstrap Form class
5085 * @cfg {String} method GET | POST (default POST)
5086 * @cfg {String} labelAlign top | left (default top)
5087 * @cfg {String} align left | right - for navbars
5092 * @param {Object} config The config object
5096 Roo.bootstrap.Form = function(config){
5097 Roo.bootstrap.Form.superclass.constructor.call(this, config);
5100 * @event clientvalidation
5101 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
5102 * @param {Form} this
5103 * @param {Boolean} valid true if the form has passed client-side validation
5105 clientvalidation: true,
5107 * @event beforeaction
5108 * Fires before any action is performed. Return false to cancel the action.
5109 * @param {Form} this
5110 * @param {Action} action The action to be performed
5114 * @event actionfailed
5115 * Fires when an action fails.
5116 * @param {Form} this
5117 * @param {Action} action The action that failed
5119 actionfailed : true,
5121 * @event actioncomplete
5122 * Fires when an action is completed.
5123 * @param {Form} this
5124 * @param {Action} action The action that completed
5126 actioncomplete : true
5131 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
5134 * @cfg {String} method
5135 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
5140 * The URL to use for form actions if one isn't supplied in the action options.
5143 * @cfg {Boolean} fileUpload
5144 * Set to true if this form is a file upload.
5148 * @cfg {Object} baseParams
5149 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
5153 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
5157 * @cfg {Sting} align (left|right) for navbar forms
5162 activeAction : null,
5165 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5166 * element by passing it or its id or mask the form itself by passing in true.
5169 waitMsgTarget : false,
5174 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5175 * element by passing it or its id or mask the form itself by passing in true.
5179 getAutoCreate : function(){
5183 method : this.method || 'POST',
5184 id : this.id || Roo.id(),
5187 if (this.parent().xtype.match(/^Nav/)) {
5188 cfg.cls = 'navbar-form navbar-' + this.align;
5192 if (this.labelAlign == 'left' ) {
5193 cfg.cls += ' form-horizontal';
5199 initEvents : function()
5201 this.el.on('submit', this.onSubmit, this);
5206 onSubmit : function(e){
5211 * Returns true if client-side validation on the form is successful.
5214 isValid : function(){
5215 var items = this.getItems();
5217 items.each(function(f){
5226 * Returns true if any fields in this form have changed since their original load.
5229 isDirty : function(){
5231 var items = this.getItems();
5232 items.each(function(f){
5242 * Performs a predefined action (submit or load) or custom actions you define on this form.
5243 * @param {String} actionName The name of the action type
5244 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
5245 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
5246 * accept other config options):
5248 Property Type Description
5249 ---------------- --------------- ----------------------------------------------------------------------------------
5250 url String The url for the action (defaults to the form's url)
5251 method String The form method to use (defaults to the form's method, or POST if not defined)
5252 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
5253 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
5254 validate the form on the client (defaults to false)
5256 * @return {BasicForm} this
5258 doAction : function(action, options){
5259 if(typeof action == 'string'){
5260 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
5262 if(this.fireEvent('beforeaction', this, action) !== false){
5263 this.beforeAction(action);
5264 action.run.defer(100, action);
5270 beforeAction : function(action){
5271 var o = action.options;
5273 // not really supported yet.. ??
5275 //if(this.waitMsgTarget === true){
5276 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
5277 //}else if(this.waitMsgTarget){
5278 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
5279 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
5281 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
5287 afterAction : function(action, success){
5288 this.activeAction = null;
5289 var o = action.options;
5291 //if(this.waitMsgTarget === true){
5293 //}else if(this.waitMsgTarget){
5294 // this.waitMsgTarget.unmask();
5296 // Roo.MessageBox.updateProgress(1);
5297 // Roo.MessageBox.hide();
5304 Roo.callback(o.success, o.scope, [this, action]);
5305 this.fireEvent('actioncomplete', this, action);
5309 // failure condition..
5310 // we have a scenario where updates need confirming.
5311 // eg. if a locking scenario exists..
5312 // we look for { errors : { needs_confirm : true }} in the response.
5314 (typeof(action.result) != 'undefined') &&
5315 (typeof(action.result.errors) != 'undefined') &&
5316 (typeof(action.result.errors.needs_confirm) != 'undefined')
5319 Roo.log("not supported yet");
5322 Roo.MessageBox.confirm(
5323 "Change requires confirmation",
5324 action.result.errorMsg,
5329 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
5339 Roo.callback(o.failure, o.scope, [this, action]);
5340 // show an error message if no failed handler is set..
5341 if (!this.hasListener('actionfailed')) {
5342 Roo.log("need to add dialog support");
5344 Roo.MessageBox.alert("Error",
5345 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
5346 action.result.errorMsg :
5347 "Saving Failed, please check your entries or try again"
5352 this.fireEvent('actionfailed', this, action);
5357 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
5358 * @param {String} id The value to search for
5361 findField : function(id){
5362 var items = this.getItems();
5363 var field = items.get(id);
5365 items.each(function(f){
5366 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
5373 return field || null;
5376 * Mark fields in this form invalid in bulk.
5377 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
5378 * @return {BasicForm} this
5380 markInvalid : function(errors){
5381 if(errors instanceof Array){
5382 for(var i = 0, len = errors.length; i < len; i++){
5383 var fieldError = errors[i];
5384 var f = this.findField(fieldError.id);
5386 f.markInvalid(fieldError.msg);
5392 if(typeof errors[id] != 'function' && (field = this.findField(id))){
5393 field.markInvalid(errors[id]);
5397 //Roo.each(this.childForms || [], function (f) {
5398 // f.markInvalid(errors);
5405 * Set values for fields in this form in bulk.
5406 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
5407 * @return {BasicForm} this
5409 setValues : function(values){
5410 if(values instanceof Array){ // array of objects
5411 for(var i = 0, len = values.length; i < len; i++){
5413 var f = this.findField(v.id);
5415 f.setValue(v.value);
5416 if(this.trackResetOnLoad){
5417 f.originalValue = f.getValue();
5421 }else{ // object hash
5424 if(typeof values[id] != 'function' && (field = this.findField(id))){
5426 if (field.setFromData &&
5428 field.displayField &&
5429 // combos' with local stores can
5430 // be queried via setValue()
5431 // to set their value..
5432 (field.store && !field.store.isLocal)
5436 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
5437 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
5438 field.setFromData(sd);
5441 field.setValue(values[id]);
5445 if(this.trackResetOnLoad){
5446 field.originalValue = field.getValue();
5452 //Roo.each(this.childForms || [], function (f) {
5453 // f.setValues(values);
5460 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
5461 * they are returned as an array.
5462 * @param {Boolean} asString
5465 getValues : function(asString){
5466 //if (this.childForms) {
5467 // copy values from the child forms
5468 // Roo.each(this.childForms, function (f) {
5469 // this.setValues(f.getValues());
5475 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
5476 if(asString === true){
5479 return Roo.urlDecode(fs);
5483 * Returns the fields in this form as an object with key/value pairs.
5484 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
5487 getFieldValues : function(with_hidden)
5489 var items = this.getItems();
5491 items.each(function(f){
5495 var v = f.getValue();
5496 if (f.inputType =='radio') {
5497 if (typeof(ret[f.getName()]) == 'undefined') {
5498 ret[f.getName()] = ''; // empty..
5501 if (!f.el.dom.checked) {
5509 // not sure if this supported any more..
5510 if ((typeof(v) == 'object') && f.getRawValue) {
5511 v = f.getRawValue() ; // dates..
5513 // combo boxes where name != hiddenName...
5514 if (f.name != f.getName()) {
5515 ret[f.name] = f.getRawValue();
5517 ret[f.getName()] = v;
5524 * Clears all invalid messages in this form.
5525 * @return {BasicForm} this
5527 clearInvalid : function(){
5528 var items = this.getItems();
5530 items.each(function(f){
5541 * @return {BasicForm} this
5544 var items = this.getItems();
5545 items.each(function(f){
5549 Roo.each(this.childForms || [], function (f) {
5556 getItems : function()
5558 var r=new Roo.util.MixedCollection(false, function(o){
5559 return o.id || (o.id = Roo.id());
5561 var iter = function(el) {
5568 Roo.each(el.items,function(e) {
5587 * Ext JS Library 1.1.1
5588 * Copyright(c) 2006-2007, Ext JS, LLC.
5590 * Originally Released Under LGPL - original licence link has changed is not relivant.
5593 * <script type="text/javascript">
5596 * @class Roo.form.VTypes
5597 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
5600 Roo.form.VTypes = function(){
5601 // closure these in so they are only created once.
5602 var alpha = /^[a-zA-Z_]+$/;
5603 var alphanum = /^[a-zA-Z0-9_]+$/;
5604 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
5605 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
5607 // All these messages and functions are configurable
5610 * The function used to validate email addresses
5611 * @param {String} value The email address
5613 'email' : function(v){
5614 return email.test(v);
5617 * The error text to display when the email validation function returns false
5620 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
5622 * The keystroke filter mask to be applied on email input
5625 'emailMask' : /[a-z0-9_\.\-@]/i,
5628 * The function used to validate URLs
5629 * @param {String} value The URL
5631 'url' : function(v){
5635 * The error text to display when the url validation function returns false
5638 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
5641 * The function used to validate alpha values
5642 * @param {String} value The value
5644 'alpha' : function(v){
5645 return alpha.test(v);
5648 * The error text to display when the alpha validation function returns false
5651 'alphaText' : 'This field should only contain letters and _',
5653 * The keystroke filter mask to be applied on alpha input
5656 'alphaMask' : /[a-z_]/i,
5659 * The function used to validate alphanumeric values
5660 * @param {String} value The value
5662 'alphanum' : function(v){
5663 return alphanum.test(v);
5666 * The error text to display when the alphanumeric validation function returns false
5669 'alphanumText' : 'This field should only contain letters, numbers and _',
5671 * The keystroke filter mask to be applied on alphanumeric input
5674 'alphanumMask' : /[a-z0-9_]/i
5684 * @class Roo.bootstrap.Input
5685 * @extends Roo.bootstrap.Component
5686 * Bootstrap Input class
5687 * @cfg {Boolean} disabled is it disabled
5688 * @cfg {String} fieldLabel - the label associated
5689 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
5690 * @cfg {String} name name of the input
5691 * @cfg {string} fieldLabel - the label associated
5692 * @cfg {string} inputType - input / file submit ...
5693 * @cfg {string} placeholder - placeholder to put in text.
5694 * @cfg {string} before - input group add on before
5695 * @cfg {string} after - input group add on after
5696 * @cfg {string} size - (lg|sm) or leave empty..
5697 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
5698 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
5699 * @cfg {Number} md colspan out of 12 for computer-sized screens
5700 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
5701 * @cfg {string} value default value of the input
5702 * @cfg {Number} labelWidth set the width of label (0-12)
5703 * @cfg {String} labelAlign (top|left)
5704 * @cfg {Boolean} readOnly Specifies that the field should be read-only
5708 * Create a new Input
5709 * @param {Object} config The config object
5712 Roo.bootstrap.Input = function(config){
5713 Roo.bootstrap.Input.superclass.constructor.call(this, config);
5718 * Fires when this field receives input focus.
5719 * @param {Roo.form.Field} this
5724 * Fires when this field loses input focus.
5725 * @param {Roo.form.Field} this
5730 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
5731 * {@link Roo.EventObject#getKey} to determine which key was pressed.
5732 * @param {Roo.form.Field} this
5733 * @param {Roo.EventObject} e The event object
5738 * Fires just before the field blurs if the field value has changed.
5739 * @param {Roo.form.Field} this
5740 * @param {Mixed} newValue The new value
5741 * @param {Mixed} oldValue The original value
5746 * Fires after the field has been marked as invalid.
5747 * @param {Roo.form.Field} this
5748 * @param {String} msg The validation message
5753 * Fires after the field has been validated with no errors.
5754 * @param {Roo.form.Field} this
5759 * Fires after the key up
5760 * @param {Roo.form.Field} this
5761 * @param {Roo.EventObject} e The event Object
5767 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
5769 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
5770 automatic validation (defaults to "keyup").
5772 validationEvent : "keyup",
5774 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
5776 validateOnBlur : true,
5778 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
5780 validationDelay : 250,
5782 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
5784 focusClass : "x-form-focus", // not needed???
5788 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
5790 invalidClass : "has-error",
5793 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
5795 selectOnFocus : false,
5798 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
5802 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
5807 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
5809 disableKeyFilter : false,
5812 * @cfg {Boolean} disabled True to disable the field (defaults to false).
5816 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
5820 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
5822 blankText : "This field is required",
5825 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
5829 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
5831 maxLength : Number.MAX_VALUE,
5833 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
5835 minLengthText : "The minimum length for this field is {0}",
5837 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
5839 maxLengthText : "The maximum length for this field is {0}",
5843 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
5844 * If available, this function will be called only after the basic validators all return true, and will be passed the
5845 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
5849 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
5850 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
5851 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
5855 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
5878 parentLabelAlign : function()
5881 while (parent.parent()) {
5882 parent = parent.parent();
5883 if (typeof(parent.labelAlign) !='undefined') {
5884 return parent.labelAlign;
5891 getAutoCreate : function(){
5893 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
5899 if(this.inputType != 'hidden'){
5900 cfg.cls = 'form-group' //input-group
5906 type : this.inputType,
5908 cls : 'form-control',
5909 placeholder : this.placeholder || ''
5913 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
5914 input.maxLength = this.maxLength;
5917 if (this.disabled) {
5918 input.disabled=true;
5921 if (this.readOnly) {
5922 input.readonly=true;
5926 input.name = this.name;
5929 input.cls += ' input-' + this.size;
5932 ['xs','sm','md','lg'].map(function(size){
5933 if (settings[size]) {
5934 cfg.cls += ' col-' + size + '-' + settings[size];
5938 var inputblock = input;
5940 if (this.before || this.after) {
5943 cls : 'input-group',
5946 if (this.before && typeof(this.before) == 'string') {
5948 inputblock.cn.push({
5950 cls : 'roo-input-before input-group-addon',
5954 if (this.before && typeof(this.before) == 'object') {
5955 this.before = Roo.factory(this.before);
5956 Roo.log(this.before);
5957 inputblock.cn.push({
5959 cls : 'roo-input-before input-group-' +
5960 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
5964 inputblock.cn.push(input);
5966 if (this.after && typeof(this.after) == 'string') {
5967 inputblock.cn.push({
5969 cls : 'roo-input-after input-group-addon',
5973 if (this.after && typeof(this.after) == 'object') {
5974 this.after = Roo.factory(this.after);
5975 Roo.log(this.after);
5976 inputblock.cn.push({
5978 cls : 'roo-input-after input-group-' +
5979 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
5984 if (align ==='left' && this.fieldLabel.length) {
5985 Roo.log("left and has label");
5991 cls : 'control-label col-sm-' + this.labelWidth,
5992 html : this.fieldLabel
5996 cls : "col-sm-" + (12 - this.labelWidth),
6003 } else if ( this.fieldLabel.length) {
6009 //cls : 'input-group-addon',
6010 html : this.fieldLabel
6020 Roo.log(" no label && no align");
6029 Roo.log('input-parentType: ' + this.parentType);
6031 if (this.parentType === 'Navbar' && this.parent().bar) {
6032 cfg.cls += ' navbar-form';
6040 * return the real input element.
6042 inputEl: function ()
6044 return this.el.select('input.form-control',true).first();
6046 setDisabled : function(v)
6048 var i = this.inputEl().dom;
6050 i.removeAttribute('disabled');
6054 i.setAttribute('disabled','true');
6056 initEvents : function()
6059 this.inputEl().on("keydown" , this.fireKey, this);
6060 this.inputEl().on("focus", this.onFocus, this);
6061 this.inputEl().on("blur", this.onBlur, this);
6063 this.inputEl().relayEvent('keyup', this);
6065 // reference to original value for reset
6066 this.originalValue = this.getValue();
6067 //Roo.form.TextField.superclass.initEvents.call(this);
6068 if(this.validationEvent == 'keyup'){
6069 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
6070 this.inputEl().on('keyup', this.filterValidation, this);
6072 else if(this.validationEvent !== false){
6073 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
6076 if(this.selectOnFocus){
6077 this.on("focus", this.preFocus, this);
6080 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
6081 this.inputEl().on("keypress", this.filterKeys, this);
6084 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
6085 this.el.on("click", this.autoSize, this);
6088 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
6089 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
6092 if (typeof(this.before) == 'object') {
6093 this.before.render(this.el.select('.roo-input-before',true).first());
6095 if (typeof(this.after) == 'object') {
6096 this.after.render(this.el.select('.roo-input-after',true).first());
6101 filterValidation : function(e){
6102 if(!e.isNavKeyPress()){
6103 this.validationTask.delay(this.validationDelay);
6107 * Validates the field value
6108 * @return {Boolean} True if the value is valid, else false
6110 validate : function(){
6111 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
6112 if(this.disabled || this.validateValue(this.getRawValue())){
6113 this.clearInvalid();
6121 * Validates a value according to the field's validation rules and marks the field as invalid
6122 * if the validation fails
6123 * @param {Mixed} value The value to validate
6124 * @return {Boolean} True if the value is valid, else false
6126 validateValue : function(value){
6127 if(value.length < 1) { // if it's blank
6128 if(this.allowBlank){
6129 this.clearInvalid();
6132 this.markInvalid(this.blankText);
6136 if(value.length < this.minLength){
6137 this.markInvalid(String.format(this.minLengthText, this.minLength));
6140 if(value.length > this.maxLength){
6141 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
6145 var vt = Roo.form.VTypes;
6146 if(!vt[this.vtype](value, this)){
6147 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
6151 if(typeof this.validator == "function"){
6152 var msg = this.validator(value);
6154 this.markInvalid(msg);
6158 if(this.regex && !this.regex.test(value)){
6159 this.markInvalid(this.regexText);
6168 fireKey : function(e){
6169 //Roo.log('field ' + e.getKey());
6170 if(e.isNavKeyPress()){
6171 this.fireEvent("specialkey", this, e);
6174 focus : function (selectText){
6176 this.inputEl().focus();
6177 if(selectText === true){
6178 this.inputEl().dom.select();
6184 onFocus : function(){
6185 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6186 // this.el.addClass(this.focusClass);
6189 this.hasFocus = true;
6190 this.startValue = this.getValue();
6191 this.fireEvent("focus", this);
6195 beforeBlur : Roo.emptyFn,
6199 onBlur : function(){
6201 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6202 //this.el.removeClass(this.focusClass);
6204 this.hasFocus = false;
6205 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
6208 var v = this.getValue();
6209 if(String(v) !== String(this.startValue)){
6210 this.fireEvent('change', this, v, this.startValue);
6212 this.fireEvent("blur", this);
6216 * Resets the current field value to the originally loaded value and clears any validation messages
6219 this.setValue(this.originalValue);
6220 this.clearInvalid();
6223 * Returns the name of the field
6224 * @return {Mixed} name The name field
6226 getName: function(){
6230 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
6231 * @return {Mixed} value The field value
6233 getValue : function(){
6234 return this.inputEl().getValue();
6237 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
6238 * @return {Mixed} value The field value
6240 getRawValue : function(){
6241 var v = this.inputEl().getValue();
6247 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
6248 * @param {Mixed} value The value to set
6250 setRawValue : function(v){
6251 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6254 selectText : function(start, end){
6255 var v = this.getRawValue();
6257 start = start === undefined ? 0 : start;
6258 end = end === undefined ? v.length : end;
6259 var d = this.inputEl().dom;
6260 if(d.setSelectionRange){
6261 d.setSelectionRange(start, end);
6262 }else if(d.createTextRange){
6263 var range = d.createTextRange();
6264 range.moveStart("character", start);
6265 range.moveEnd("character", v.length-end);
6272 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
6273 * @param {Mixed} value The value to set
6275 setValue : function(v){
6278 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6284 processValue : function(value){
6285 if(this.stripCharsRe){
6286 var newValue = value.replace(this.stripCharsRe, '');
6287 if(newValue !== value){
6288 this.setRawValue(newValue);
6295 preFocus : function(){
6297 if(this.selectOnFocus){
6298 this.inputEl().dom.select();
6301 filterKeys : function(e){
6303 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
6306 var c = e.getCharCode(), cc = String.fromCharCode(c);
6307 if(Roo.isIE && (e.isSpecialKey() || !cc)){
6310 if(!this.maskRe.test(cc)){
6315 * Clear any invalid styles/messages for this field
6317 clearInvalid : function(){
6319 if(!this.el || this.preventMark){ // not rendered
6322 this.el.removeClass(this.invalidClass);
6324 switch(this.msgTarget){
6326 this.el.dom.qtip = '';
6329 this.el.dom.title = '';
6333 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
6338 this.errorIcon.dom.qtip = '';
6339 this.errorIcon.hide();
6340 this.un('resize', this.alignErrorIcon, this);
6344 var t = Roo.getDom(this.msgTarget);
6346 t.style.display = 'none';
6350 this.fireEvent('valid', this);
6353 * Mark this field as invalid
6354 * @param {String} msg The validation message
6356 markInvalid : function(msg){
6357 if(!this.el || this.preventMark){ // not rendered
6360 this.el.addClass(this.invalidClass);
6362 msg = msg || this.invalidText;
6363 switch(this.msgTarget){
6365 this.el.dom.qtip = msg;
6366 this.el.dom.qclass = 'x-form-invalid-tip';
6367 if(Roo.QuickTips){ // fix for floating editors interacting with DND
6368 Roo.QuickTips.enable();
6372 this.el.dom.title = msg;
6376 var elp = this.el.findParent('.x-form-element', 5, true);
6377 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
6378 this.errorEl.setWidth(elp.getWidth(true)-20);
6380 this.errorEl.update(msg);
6381 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
6384 if(!this.errorIcon){
6385 var elp = this.el.findParent('.x-form-element', 5, true);
6386 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
6388 this.alignErrorIcon();
6389 this.errorIcon.dom.qtip = msg;
6390 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
6391 this.errorIcon.show();
6392 this.on('resize', this.alignErrorIcon, this);
6395 var t = Roo.getDom(this.msgTarget);
6397 t.style.display = this.msgDisplay;
6401 this.fireEvent('invalid', this, msg);
6404 SafariOnKeyDown : function(event)
6406 // this is a workaround for a password hang bug on chrome/ webkit.
6408 var isSelectAll = false;
6410 if(this.inputEl().dom.selectionEnd > 0){
6411 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
6413 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
6414 event.preventDefault();
6419 if(isSelectAll){ // backspace and delete key
6421 event.preventDefault();
6422 // this is very hacky as keydown always get's upper case.
6424 var cc = String.fromCharCode(event.getCharCode());
6425 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
6429 adjustWidth : function(tag, w){
6430 tag = tag.toLowerCase();
6431 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
6432 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
6436 if(tag == 'textarea'){
6439 }else if(Roo.isOpera){
6443 if(tag == 'textarea'){
6462 * @class Roo.bootstrap.TextArea
6463 * @extends Roo.bootstrap.Input
6464 * Bootstrap TextArea class
6465 * @cfg {Number} cols Specifies the visible width of a text area
6466 * @cfg {Number} rows Specifies the visible number of lines in a text area
6467 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
6468 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
6469 * @cfg {string} html text
6472 * Create a new TextArea
6473 * @param {Object} config The config object
6476 Roo.bootstrap.TextArea = function(config){
6477 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
6481 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
6491 getAutoCreate : function(){
6493 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6504 value : this.value || '',
6505 html: this.html || '',
6506 cls : 'form-control',
6507 placeholder : this.placeholder || ''
6511 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6512 input.maxLength = this.maxLength;
6516 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
6520 input.cols = this.cols;
6523 if (this.readOnly) {
6524 input.readonly = true;
6528 input.name = this.name;
6532 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
6536 ['xs','sm','md','lg'].map(function(size){
6537 if (settings[size]) {
6538 cfg.cls += ' col-' + size + '-' + settings[size];
6542 var inputblock = input;
6544 if (this.before || this.after) {
6547 cls : 'input-group',
6551 inputblock.cn.push({
6553 cls : 'input-group-addon',
6557 inputblock.cn.push(input);
6559 inputblock.cn.push({
6561 cls : 'input-group-addon',
6568 if (align ==='left' && this.fieldLabel.length) {
6569 Roo.log("left and has label");
6575 cls : 'control-label col-sm-' + this.labelWidth,
6576 html : this.fieldLabel
6580 cls : "col-sm-" + (12 - this.labelWidth),
6587 } else if ( this.fieldLabel.length) {
6593 //cls : 'input-group-addon',
6594 html : this.fieldLabel
6604 Roo.log(" no label && no align");
6614 if (this.disabled) {
6615 input.disabled=true;
6622 * return the real textarea element.
6624 inputEl: function ()
6626 return this.el.select('textarea.form-control',true).first();
6634 * trigger field - base class for combo..
6639 * @class Roo.bootstrap.TriggerField
6640 * @extends Roo.bootstrap.Input
6641 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
6642 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
6643 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
6644 * for which you can provide a custom implementation. For example:
6646 var trigger = new Roo.bootstrap.TriggerField();
6647 trigger.onTriggerClick = myTriggerFn;
6648 trigger.applyTo('my-field');
6651 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
6652 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
6653 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
6654 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
6656 * Create a new TriggerField.
6657 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
6658 * to the base TextField)
6660 Roo.bootstrap.TriggerField = function(config){
6661 this.mimicing = false;
6662 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
6665 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
6667 * @cfg {String} triggerClass A CSS class to apply to the trigger
6670 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
6674 /** @cfg {Boolean} grow @hide */
6675 /** @cfg {Number} growMin @hide */
6676 /** @cfg {Number} growMax @hide */
6682 autoSize: Roo.emptyFn,
6689 actionMode : 'wrap',
6693 getAutoCreate : function(){
6695 var parent = this.parent();
6697 var align = this.labelAlign || this.parentLabelAlign();
6702 cls: 'form-group' //input-group
6709 type : this.inputType,
6710 cls : 'form-control',
6711 autocomplete: 'off',
6712 placeholder : this.placeholder || ''
6716 input.name = this.name;
6719 input.cls += ' input-' + this.size;
6722 if (this.disabled) {
6723 input.disabled=true;
6726 var inputblock = input;
6728 if (this.before || this.after) {
6731 cls : 'input-group',
6735 inputblock.cn.push({
6737 cls : 'input-group-addon',
6741 inputblock.cn.push(input);
6743 inputblock.cn.push({
6745 cls : 'input-group-addon',
6758 cls: 'form-hidden-field'
6766 Roo.log('multiple');
6774 cls: 'form-hidden-field'
6778 cls: 'select2-choices',
6782 cls: 'select2-search-field',
6795 cls: 'select2-container input-group',
6800 cls: 'typeahead typeahead-long dropdown-menu',
6801 style: 'display:none'
6809 cls : 'input-group-addon btn dropdown-toggle',
6817 cls: 'combobox-clear',
6831 combobox.cls += ' select2-container-multi';
6834 if (align ==='left' && this.fieldLabel.length) {
6836 Roo.log("left and has label");
6842 cls : 'control-label col-sm-' + this.labelWidth,
6843 html : this.fieldLabel
6847 cls : "col-sm-" + (12 - this.labelWidth),
6854 } else if ( this.fieldLabel.length) {
6860 //cls : 'input-group-addon',
6861 html : this.fieldLabel
6871 Roo.log(" no label && no align");
6878 ['xs','sm','md','lg'].map(function(size){
6879 if (settings[size]) {
6880 cfg.cls += ' col-' + size + '-' + settings[size];
6891 onResize : function(w, h){
6892 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
6893 // if(typeof w == 'number'){
6894 // var x = w - this.trigger.getWidth();
6895 // this.inputEl().setWidth(this.adjustWidth('input', x));
6896 // this.trigger.setStyle('left', x+'px');
6901 adjustSize : Roo.BoxComponent.prototype.adjustSize,
6904 getResizeEl : function(){
6905 return this.inputEl();
6909 getPositionEl : function(){
6910 return this.inputEl();
6914 alignErrorIcon : function(){
6915 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
6919 initEvents : function(){
6921 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
6922 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
6924 this.trigger = this.el.select('span.dropdown-toggle',true).first();
6925 if(this.hideTrigger){
6926 this.trigger.setDisplayed(false);
6928 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
6932 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
6935 //this.trigger.addClassOnOver('x-form-trigger-over');
6936 //this.trigger.addClassOnClick('x-form-trigger-click');
6939 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
6944 initTrigger : function(){
6949 onDestroy : function(){
6951 this.trigger.removeAllListeners();
6952 // this.trigger.remove();
6955 // this.wrap.remove();
6957 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
6961 onFocus : function(){
6962 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
6965 this.wrap.addClass('x-trigger-wrap-focus');
6966 this.mimicing = true;
6967 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
6968 if(this.monitorTab){
6969 this.el.on("keydown", this.checkTab, this);
6976 checkTab : function(e){
6977 if(e.getKey() == e.TAB){
6983 onBlur : function(){
6988 mimicBlur : function(e, t){
6990 if(!this.wrap.contains(t) && this.validateBlur()){
6997 triggerBlur : function(){
6998 this.mimicing = false;
6999 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
7000 if(this.monitorTab){
7001 this.el.un("keydown", this.checkTab, this);
7003 //this.wrap.removeClass('x-trigger-wrap-focus');
7004 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
7008 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
7009 validateBlur : function(e, t){
7014 onDisable : function(){
7015 this.inputEl().dom.disabled = true;
7016 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
7018 // this.wrap.addClass('x-item-disabled');
7023 onEnable : function(){
7024 this.inputEl().dom.disabled = false;
7025 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
7027 // this.el.removeClass('x-item-disabled');
7032 onShow : function(){
7033 var ae = this.getActionEl();
7036 ae.dom.style.display = '';
7037 ae.dom.style.visibility = 'visible';
7043 onHide : function(){
7044 var ae = this.getActionEl();
7045 ae.dom.style.display = 'none';
7049 * The function that should handle the trigger's click event. This method does nothing by default until overridden
7050 * by an implementing function.
7052 * @param {EventObject} e
7054 onTriggerClick : Roo.emptyFn
7058 * Ext JS Library 1.1.1
7059 * Copyright(c) 2006-2007, Ext JS, LLC.
7061 * Originally Released Under LGPL - original licence link has changed is not relivant.
7064 * <script type="text/javascript">
7069 * @class Roo.data.SortTypes
7071 * Defines the default sorting (casting?) comparison functions used when sorting data.
7073 Roo.data.SortTypes = {
7075 * Default sort that does nothing
7076 * @param {Mixed} s The value being converted
7077 * @return {Mixed} The comparison value
7084 * The regular expression used to strip tags
7088 stripTagsRE : /<\/?[^>]+>/gi,
7091 * Strips all HTML tags to sort on text only
7092 * @param {Mixed} s The value being converted
7093 * @return {String} The comparison value
7095 asText : function(s){
7096 return String(s).replace(this.stripTagsRE, "");
7100 * Strips all HTML tags to sort on text only - Case insensitive
7101 * @param {Mixed} s The value being converted
7102 * @return {String} The comparison value
7104 asUCText : function(s){
7105 return String(s).toUpperCase().replace(this.stripTagsRE, "");
7109 * Case insensitive string
7110 * @param {Mixed} s The value being converted
7111 * @return {String} The comparison value
7113 asUCString : function(s) {
7114 return String(s).toUpperCase();
7119 * @param {Mixed} s The value being converted
7120 * @return {Number} The comparison value
7122 asDate : function(s) {
7126 if(s instanceof Date){
7129 return Date.parse(String(s));
7134 * @param {Mixed} s The value being converted
7135 * @return {Float} The comparison value
7137 asFloat : function(s) {
7138 var val = parseFloat(String(s).replace(/,/g, ""));
7139 if(isNaN(val)) val = 0;
7145 * @param {Mixed} s The value being converted
7146 * @return {Number} The comparison value
7148 asInt : function(s) {
7149 var val = parseInt(String(s).replace(/,/g, ""));
7150 if(isNaN(val)) val = 0;
7155 * Ext JS Library 1.1.1
7156 * Copyright(c) 2006-2007, Ext JS, LLC.
7158 * Originally Released Under LGPL - original licence link has changed is not relivant.
7161 * <script type="text/javascript">
7165 * @class Roo.data.Record
7166 * Instances of this class encapsulate both record <em>definition</em> information, and record
7167 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
7168 * to access Records cached in an {@link Roo.data.Store} object.<br>
7170 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
7171 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
7174 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
7176 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
7177 * {@link #create}. The parameters are the same.
7178 * @param {Array} data An associative Array of data values keyed by the field name.
7179 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
7180 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
7181 * not specified an integer id is generated.
7183 Roo.data.Record = function(data, id){
7184 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
7189 * Generate a constructor for a specific record layout.
7190 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
7191 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
7192 * Each field definition object may contain the following properties: <ul>
7193 * <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,
7194 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
7195 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
7196 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
7197 * is being used, then this is a string containing the javascript expression to reference the data relative to
7198 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
7199 * to the data item relative to the record element. If the mapping expression is the same as the field name,
7200 * this may be omitted.</p></li>
7201 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
7202 * <ul><li>auto (Default, implies no conversion)</li>
7207 * <li>date</li></ul></p></li>
7208 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
7209 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
7210 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
7211 * by the Reader into an object that will be stored in the Record. It is passed the
7212 * following parameters:<ul>
7213 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
7215 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
7217 * <br>usage:<br><pre><code>
7218 var TopicRecord = Roo.data.Record.create(
7219 {name: 'title', mapping: 'topic_title'},
7220 {name: 'author', mapping: 'username'},
7221 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
7222 {name: 'lastPost', mapping: 'post_time', type: 'date'},
7223 {name: 'lastPoster', mapping: 'user2'},
7224 {name: 'excerpt', mapping: 'post_text'}
7227 var myNewRecord = new TopicRecord({
7228 title: 'Do my job please',
7231 lastPost: new Date(),
7232 lastPoster: 'Animal',
7233 excerpt: 'No way dude!'
7235 myStore.add(myNewRecord);
7240 Roo.data.Record.create = function(o){
7242 f.superclass.constructor.apply(this, arguments);
7244 Roo.extend(f, Roo.data.Record);
7245 var p = f.prototype;
7246 p.fields = new Roo.util.MixedCollection(false, function(field){
7249 for(var i = 0, len = o.length; i < len; i++){
7250 p.fields.add(new Roo.data.Field(o[i]));
7252 f.getField = function(name){
7253 return p.fields.get(name);
7258 Roo.data.Record.AUTO_ID = 1000;
7259 Roo.data.Record.EDIT = 'edit';
7260 Roo.data.Record.REJECT = 'reject';
7261 Roo.data.Record.COMMIT = 'commit';
7263 Roo.data.Record.prototype = {
7265 * Readonly flag - true if this record has been modified.
7274 join : function(store){
7279 * Set the named field to the specified value.
7280 * @param {String} name The name of the field to set.
7281 * @param {Object} value The value to set the field to.
7283 set : function(name, value){
7284 if(this.data[name] == value){
7291 if(typeof this.modified[name] == 'undefined'){
7292 this.modified[name] = this.data[name];
7294 this.data[name] = value;
7295 if(!this.editing && this.store){
7296 this.store.afterEdit(this);
7301 * Get the value of the named field.
7302 * @param {String} name The name of the field to get the value of.
7303 * @return {Object} The value of the field.
7305 get : function(name){
7306 return this.data[name];
7310 beginEdit : function(){
7311 this.editing = true;
7316 cancelEdit : function(){
7317 this.editing = false;
7318 delete this.modified;
7322 endEdit : function(){
7323 this.editing = false;
7324 if(this.dirty && this.store){
7325 this.store.afterEdit(this);
7330 * Usually called by the {@link Roo.data.Store} which owns the Record.
7331 * Rejects all changes made to the Record since either creation, or the last commit operation.
7332 * Modified fields are reverted to their original values.
7334 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
7335 * of reject operations.
7337 reject : function(){
7338 var m = this.modified;
7340 if(typeof m[n] != "function"){
7341 this.data[n] = m[n];
7345 delete this.modified;
7346 this.editing = false;
7348 this.store.afterReject(this);
7353 * Usually called by the {@link Roo.data.Store} which owns the Record.
7354 * Commits all changes made to the Record since either creation, or the last commit operation.
7356 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
7357 * of commit operations.
7359 commit : function(){
7361 delete this.modified;
7362 this.editing = false;
7364 this.store.afterCommit(this);
7369 hasError : function(){
7370 return this.error != null;
7374 clearError : function(){
7379 * Creates a copy of this record.
7380 * @param {String} id (optional) A new record id if you don't want to use this record's id
7383 copy : function(newId) {
7384 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
7388 * Ext JS Library 1.1.1
7389 * Copyright(c) 2006-2007, Ext JS, LLC.
7391 * Originally Released Under LGPL - original licence link has changed is not relivant.
7394 * <script type="text/javascript">
7400 * @class Roo.data.Store
7401 * @extends Roo.util.Observable
7402 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
7403 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
7405 * 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
7406 * has no knowledge of the format of the data returned by the Proxy.<br>
7408 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
7409 * instances from the data object. These records are cached and made available through accessor functions.
7411 * Creates a new Store.
7412 * @param {Object} config A config object containing the objects needed for the Store to access data,
7413 * and read the data into Records.
7415 Roo.data.Store = function(config){
7416 this.data = new Roo.util.MixedCollection(false);
7417 this.data.getKey = function(o){
7420 this.baseParams = {};
7427 "multisort" : "_multisort"
7430 if(config && config.data){
7431 this.inlineData = config.data;
7435 Roo.apply(this, config);
7437 if(this.reader){ // reader passed
7438 this.reader = Roo.factory(this.reader, Roo.data);
7439 this.reader.xmodule = this.xmodule || false;
7440 if(!this.recordType){
7441 this.recordType = this.reader.recordType;
7443 if(this.reader.onMetaChange){
7444 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
7448 if(this.recordType){
7449 this.fields = this.recordType.prototype.fields;
7455 * @event datachanged
7456 * Fires when the data cache has changed, and a widget which is using this Store
7457 * as a Record cache should refresh its view.
7458 * @param {Store} this
7463 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
7464 * @param {Store} this
7465 * @param {Object} meta The JSON metadata
7470 * Fires when Records have been added to the Store
7471 * @param {Store} this
7472 * @param {Roo.data.Record[]} records The array of Records added
7473 * @param {Number} index The index at which the record(s) were added
7478 * Fires when a Record has been removed from the Store
7479 * @param {Store} this
7480 * @param {Roo.data.Record} record The Record that was removed
7481 * @param {Number} index The index at which the record was removed
7486 * Fires when a Record has been updated
7487 * @param {Store} this
7488 * @param {Roo.data.Record} record The Record that was updated
7489 * @param {String} operation The update operation being performed. Value may be one of:
7491 Roo.data.Record.EDIT
7492 Roo.data.Record.REJECT
7493 Roo.data.Record.COMMIT
7499 * Fires when the data cache has been cleared.
7500 * @param {Store} this
7505 * Fires before a request is made for a new data object. If the beforeload handler returns false
7506 * the load action will be canceled.
7507 * @param {Store} this
7508 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7512 * @event beforeloadadd
7513 * Fires after a new set of Records has been loaded.
7514 * @param {Store} this
7515 * @param {Roo.data.Record[]} records The Records that were loaded
7516 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7518 beforeloadadd : true,
7521 * Fires after a new set of Records has been loaded, before they are added to the store.
7522 * @param {Store} this
7523 * @param {Roo.data.Record[]} records The Records that were loaded
7524 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7525 * @params {Object} return from reader
7529 * @event loadexception
7530 * Fires if an exception occurs in the Proxy during loading.
7531 * Called with the signature of the Proxy's "loadexception" event.
7532 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
7535 * @param {Object} return from JsonData.reader() - success, totalRecords, records
7536 * @param {Object} load options
7537 * @param {Object} jsonData from your request (normally this contains the Exception)
7539 loadexception : true
7543 this.proxy = Roo.factory(this.proxy, Roo.data);
7544 this.proxy.xmodule = this.xmodule || false;
7545 this.relayEvents(this.proxy, ["loadexception"]);
7547 this.sortToggle = {};
7548 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
7550 Roo.data.Store.superclass.constructor.call(this);
7552 if(this.inlineData){
7553 this.loadData(this.inlineData);
7554 delete this.inlineData;
7558 Roo.extend(Roo.data.Store, Roo.util.Observable, {
7560 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
7561 * without a remote query - used by combo/forms at present.
7565 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
7568 * @cfg {Array} data Inline data to be loaded when the store is initialized.
7571 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
7572 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
7575 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
7576 * on any HTTP request
7579 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
7582 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
7586 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
7587 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
7592 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
7593 * loaded or when a record is removed. (defaults to false).
7595 pruneModifiedRecords : false,
7601 * Add Records to the Store and fires the add event.
7602 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
7604 add : function(records){
7605 records = [].concat(records);
7606 for(var i = 0, len = records.length; i < len; i++){
7607 records[i].join(this);
7609 var index = this.data.length;
7610 this.data.addAll(records);
7611 this.fireEvent("add", this, records, index);
7615 * Remove a Record from the Store and fires the remove event.
7616 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
7618 remove : function(record){
7619 var index = this.data.indexOf(record);
7620 this.data.removeAt(index);
7621 if(this.pruneModifiedRecords){
7622 this.modified.remove(record);
7624 this.fireEvent("remove", this, record, index);
7628 * Remove all Records from the Store and fires the clear event.
7630 removeAll : function(){
7632 if(this.pruneModifiedRecords){
7635 this.fireEvent("clear", this);
7639 * Inserts Records to the Store at the given index and fires the add event.
7640 * @param {Number} index The start index at which to insert the passed Records.
7641 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
7643 insert : function(index, records){
7644 records = [].concat(records);
7645 for(var i = 0, len = records.length; i < len; i++){
7646 this.data.insert(index, records[i]);
7647 records[i].join(this);
7649 this.fireEvent("add", this, records, index);
7653 * Get the index within the cache of the passed Record.
7654 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
7655 * @return {Number} The index of the passed Record. Returns -1 if not found.
7657 indexOf : function(record){
7658 return this.data.indexOf(record);
7662 * Get the index within the cache of the Record with the passed id.
7663 * @param {String} id The id of the Record to find.
7664 * @return {Number} The index of the Record. Returns -1 if not found.
7666 indexOfId : function(id){
7667 return this.data.indexOfKey(id);
7671 * Get the Record with the specified id.
7672 * @param {String} id The id of the Record to find.
7673 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
7675 getById : function(id){
7676 return this.data.key(id);
7680 * Get the Record at the specified index.
7681 * @param {Number} index The index of the Record to find.
7682 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
7684 getAt : function(index){
7685 return this.data.itemAt(index);
7689 * Returns a range of Records between specified indices.
7690 * @param {Number} startIndex (optional) The starting index (defaults to 0)
7691 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
7692 * @return {Roo.data.Record[]} An array of Records
7694 getRange : function(start, end){
7695 return this.data.getRange(start, end);
7699 storeOptions : function(o){
7700 o = Roo.apply({}, o);
7703 this.lastOptions = o;
7707 * Loads the Record cache from the configured Proxy using the configured Reader.
7709 * If using remote paging, then the first load call must specify the <em>start</em>
7710 * and <em>limit</em> properties in the options.params property to establish the initial
7711 * position within the dataset, and the number of Records to cache on each read from the Proxy.
7713 * <strong>It is important to note that for remote data sources, loading is asynchronous,
7714 * and this call will return before the new data has been loaded. Perform any post-processing
7715 * in a callback function, or in a "load" event handler.</strong>
7717 * @param {Object} options An object containing properties which control loading options:<ul>
7718 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
7719 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
7720 * passed the following arguments:<ul>
7721 * <li>r : Roo.data.Record[]</li>
7722 * <li>options: Options object from the load call</li>
7723 * <li>success: Boolean success indicator</li></ul></li>
7724 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
7725 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
7728 load : function(options){
7729 options = options || {};
7730 if(this.fireEvent("beforeload", this, options) !== false){
7731 this.storeOptions(options);
7732 var p = Roo.apply(options.params || {}, this.baseParams);
7733 // if meta was not loaded from remote source.. try requesting it.
7734 if (!this.reader.metaFromRemote) {
7737 if(this.sortInfo && this.remoteSort){
7738 var pn = this.paramNames;
7739 p[pn["sort"]] = this.sortInfo.field;
7740 p[pn["dir"]] = this.sortInfo.direction;
7742 if (this.multiSort) {
7743 var pn = this.paramNames;
7744 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
7747 this.proxy.load(p, this.reader, this.loadRecords, this, options);
7752 * Reloads the Record cache from the configured Proxy using the configured Reader and
7753 * the options from the last load operation performed.
7754 * @param {Object} options (optional) An object containing properties which may override the options
7755 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
7756 * the most recently used options are reused).
7758 reload : function(options){
7759 this.load(Roo.applyIf(options||{}, this.lastOptions));
7763 // Called as a callback by the Reader during a load operation.
7764 loadRecords : function(o, options, success){
7765 if(!o || success === false){
7766 if(success !== false){
7767 this.fireEvent("load", this, [], options, o);
7769 if(options.callback){
7770 options.callback.call(options.scope || this, [], options, false);
7774 // if data returned failure - throw an exception.
7775 if (o.success === false) {
7776 // show a message if no listener is registered.
7777 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
7778 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
7780 // loadmask wil be hooked into this..
7781 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
7784 var r = o.records, t = o.totalRecords || r.length;
7786 this.fireEvent("beforeloadadd", this, r, options, o);
7788 if(!options || options.add !== true){
7789 if(this.pruneModifiedRecords){
7792 for(var i = 0, len = r.length; i < len; i++){
7796 this.data = this.snapshot;
7797 delete this.snapshot;
7800 this.data.addAll(r);
7801 this.totalLength = t;
7803 this.fireEvent("datachanged", this);
7805 this.totalLength = Math.max(t, this.data.length+r.length);
7808 this.fireEvent("load", this, r, options, o);
7809 if(options.callback){
7810 options.callback.call(options.scope || this, r, options, true);
7816 * Loads data from a passed data block. A Reader which understands the format of the data
7817 * must have been configured in the constructor.
7818 * @param {Object} data The data block from which to read the Records. The format of the data expected
7819 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
7820 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
7822 loadData : function(o, append){
7823 var r = this.reader.readRecords(o);
7824 this.loadRecords(r, {add: append}, true);
7828 * Gets the number of cached records.
7830 * <em>If using paging, this may not be the total size of the dataset. If the data object
7831 * used by the Reader contains the dataset size, then the getTotalCount() function returns
7832 * the data set size</em>
7834 getCount : function(){
7835 return this.data.length || 0;
7839 * Gets the total number of records in the dataset as returned by the server.
7841 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
7842 * the dataset size</em>
7844 getTotalCount : function(){
7845 return this.totalLength || 0;
7849 * Returns the sort state of the Store as an object with two properties:
7851 field {String} The name of the field by which the Records are sorted
7852 direction {String} The sort order, "ASC" or "DESC"
7855 getSortState : function(){
7856 return this.sortInfo;
7860 applySort : function(){
7861 if(this.sortInfo && !this.remoteSort){
7862 var s = this.sortInfo, f = s.field;
7863 var st = this.fields.get(f).sortType;
7864 var fn = function(r1, r2){
7865 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
7866 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
7868 this.data.sort(s.direction, fn);
7869 if(this.snapshot && this.snapshot != this.data){
7870 this.snapshot.sort(s.direction, fn);
7876 * Sets the default sort column and order to be used by the next load operation.
7877 * @param {String} fieldName The name of the field to sort by.
7878 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
7880 setDefaultSort : function(field, dir){
7881 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
7886 * If remote sorting is used, the sort is performed on the server, and the cache is
7887 * reloaded. If local sorting is used, the cache is sorted internally.
7888 * @param {String} fieldName The name of the field to sort by.
7889 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
7891 sort : function(fieldName, dir){
7892 var f = this.fields.get(fieldName);
7894 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
7896 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
7897 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
7902 this.sortToggle[f.name] = dir;
7903 this.sortInfo = {field: f.name, direction: dir};
7904 if(!this.remoteSort){
7906 this.fireEvent("datachanged", this);
7908 this.load(this.lastOptions);
7913 * Calls the specified function for each of the Records in the cache.
7914 * @param {Function} fn The function to call. The Record is passed as the first parameter.
7915 * Returning <em>false</em> aborts and exits the iteration.
7916 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
7918 each : function(fn, scope){
7919 this.data.each(fn, scope);
7923 * Gets all records modified since the last commit. Modified records are persisted across load operations
7924 * (e.g., during paging).
7925 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
7927 getModifiedRecords : function(){
7928 return this.modified;
7932 createFilterFn : function(property, value, anyMatch){
7933 if(!value.exec){ // not a regex
7934 value = String(value);
7935 if(value.length == 0){
7938 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
7941 return value.test(r.data[property]);
7946 * Sums the value of <i>property</i> for each record between start and end and returns the result.
7947 * @param {String} property A field on your records
7948 * @param {Number} start The record index to start at (defaults to 0)
7949 * @param {Number} end The last record index to include (defaults to length - 1)
7950 * @return {Number} The sum
7952 sum : function(property, start, end){
7953 var rs = this.data.items, v = 0;
7955 end = (end || end === 0) ? end : rs.length-1;
7957 for(var i = start; i <= end; i++){
7958 v += (rs[i].data[property] || 0);
7964 * Filter the records by a specified property.
7965 * @param {String} field A field on your records
7966 * @param {String/RegExp} value Either a string that the field
7967 * should start with or a RegExp to test against the field
7968 * @param {Boolean} anyMatch True to match any part not just the beginning
7970 filter : function(property, value, anyMatch){
7971 var fn = this.createFilterFn(property, value, anyMatch);
7972 return fn ? this.filterBy(fn) : this.clearFilter();
7976 * Filter by a function. The specified function will be called with each
7977 * record in this data source. If the function returns true the record is included,
7978 * otherwise it is filtered.
7979 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
7980 * @param {Object} scope (optional) The scope of the function (defaults to this)
7982 filterBy : function(fn, scope){
7983 this.snapshot = this.snapshot || this.data;
7984 this.data = this.queryBy(fn, scope||this);
7985 this.fireEvent("datachanged", this);
7989 * Query the records by a specified property.
7990 * @param {String} field A field on your records
7991 * @param {String/RegExp} value Either a string that the field
7992 * should start with or a RegExp to test against the field
7993 * @param {Boolean} anyMatch True to match any part not just the beginning
7994 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
7996 query : function(property, value, anyMatch){
7997 var fn = this.createFilterFn(property, value, anyMatch);
7998 return fn ? this.queryBy(fn) : this.data.clone();
8002 * Query by a function. The specified function will be called with each
8003 * record in this data source. If the function returns true the record is included
8005 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8006 * @param {Object} scope (optional) The scope of the function (defaults to this)
8007 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8009 queryBy : function(fn, scope){
8010 var data = this.snapshot || this.data;
8011 return data.filterBy(fn, scope||this);
8015 * Collects unique values for a particular dataIndex from this store.
8016 * @param {String} dataIndex The property to collect
8017 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
8018 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
8019 * @return {Array} An array of the unique values
8021 collect : function(dataIndex, allowNull, bypassFilter){
8022 var d = (bypassFilter === true && this.snapshot) ?
8023 this.snapshot.items : this.data.items;
8024 var v, sv, r = [], l = {};
8025 for(var i = 0, len = d.length; i < len; i++){
8026 v = d[i].data[dataIndex];
8028 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
8037 * Revert to a view of the Record cache with no filtering applied.
8038 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
8040 clearFilter : function(suppressEvent){
8041 if(this.snapshot && this.snapshot != this.data){
8042 this.data = this.snapshot;
8043 delete this.snapshot;
8044 if(suppressEvent !== true){
8045 this.fireEvent("datachanged", this);
8051 afterEdit : function(record){
8052 if(this.modified.indexOf(record) == -1){
8053 this.modified.push(record);
8055 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
8059 afterReject : function(record){
8060 this.modified.remove(record);
8061 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
8065 afterCommit : function(record){
8066 this.modified.remove(record);
8067 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
8071 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
8072 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
8074 commitChanges : function(){
8075 var m = this.modified.slice(0);
8077 for(var i = 0, len = m.length; i < len; i++){
8083 * Cancel outstanding changes on all changed records.
8085 rejectChanges : function(){
8086 var m = this.modified.slice(0);
8088 for(var i = 0, len = m.length; i < len; i++){
8093 onMetaChange : function(meta, rtype, o){
8094 this.recordType = rtype;
8095 this.fields = rtype.prototype.fields;
8096 delete this.snapshot;
8097 this.sortInfo = meta.sortInfo || this.sortInfo;
8099 this.fireEvent('metachange', this, this.reader.meta);
8102 moveIndex : function(data, type)
8104 var index = this.indexOf(data);
8106 var newIndex = index + type;
8110 this.insert(newIndex, data);
8115 * Ext JS Library 1.1.1
8116 * Copyright(c) 2006-2007, Ext JS, LLC.
8118 * Originally Released Under LGPL - original licence link has changed is not relivant.
8121 * <script type="text/javascript">
8125 * @class Roo.data.SimpleStore
8126 * @extends Roo.data.Store
8127 * Small helper class to make creating Stores from Array data easier.
8128 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
8129 * @cfg {Array} fields An array of field definition objects, or field name strings.
8130 * @cfg {Array} data The multi-dimensional array of data
8132 * @param {Object} config
8134 Roo.data.SimpleStore = function(config){
8135 Roo.data.SimpleStore.superclass.constructor.call(this, {
8137 reader: new Roo.data.ArrayReader({
8140 Roo.data.Record.create(config.fields)
8142 proxy : new Roo.data.MemoryProxy(config.data)
8146 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
8148 * Ext JS Library 1.1.1
8149 * Copyright(c) 2006-2007, Ext JS, LLC.
8151 * Originally Released Under LGPL - original licence link has changed is not relivant.
8154 * <script type="text/javascript">
8159 * @extends Roo.data.Store
8160 * @class Roo.data.JsonStore
8161 * Small helper class to make creating Stores for JSON data easier. <br/>
8163 var store = new Roo.data.JsonStore({
8164 url: 'get-images.php',
8166 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
8169 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
8170 * JsonReader and HttpProxy (unless inline data is provided).</b>
8171 * @cfg {Array} fields An array of field definition objects, or field name strings.
8173 * @param {Object} config
8175 Roo.data.JsonStore = function(c){
8176 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
8177 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
8178 reader: new Roo.data.JsonReader(c, c.fields)
8181 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
8183 * Ext JS Library 1.1.1
8184 * Copyright(c) 2006-2007, Ext JS, LLC.
8186 * Originally Released Under LGPL - original licence link has changed is not relivant.
8189 * <script type="text/javascript">
8193 Roo.data.Field = function(config){
8194 if(typeof config == "string"){
8195 config = {name: config};
8197 Roo.apply(this, config);
8203 var st = Roo.data.SortTypes;
8204 // named sortTypes are supported, here we look them up
8205 if(typeof this.sortType == "string"){
8206 this.sortType = st[this.sortType];
8209 // set default sortType for strings and dates
8213 this.sortType = st.asUCString;
8216 this.sortType = st.asDate;
8219 this.sortType = st.none;
8224 var stripRe = /[\$,%]/g;
8226 // prebuilt conversion function for this field, instead of
8227 // switching every time we're reading a value
8229 var cv, dateFormat = this.dateFormat;
8234 cv = function(v){ return v; };
8237 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
8241 return v !== undefined && v !== null && v !== '' ?
8242 parseInt(String(v).replace(stripRe, ""), 10) : '';
8247 return v !== undefined && v !== null && v !== '' ?
8248 parseFloat(String(v).replace(stripRe, ""), 10) : '';
8253 cv = function(v){ return v === true || v === "true" || v == 1; };
8260 if(v instanceof Date){
8264 if(dateFormat == "timestamp"){
8265 return new Date(v*1000);
8267 return Date.parseDate(v, dateFormat);
8269 var parsed = Date.parse(v);
8270 return parsed ? new Date(parsed) : null;
8279 Roo.data.Field.prototype = {
8287 * Ext JS Library 1.1.1
8288 * Copyright(c) 2006-2007, Ext JS, LLC.
8290 * Originally Released Under LGPL - original licence link has changed is not relivant.
8293 * <script type="text/javascript">
8296 // Base class for reading structured data from a data source. This class is intended to be
8297 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
8300 * @class Roo.data.DataReader
8301 * Base class for reading structured data from a data source. This class is intended to be
8302 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
8305 Roo.data.DataReader = function(meta, recordType){
8309 this.recordType = recordType instanceof Array ?
8310 Roo.data.Record.create(recordType) : recordType;
8313 Roo.data.DataReader.prototype = {
8315 * Create an empty record
8316 * @param {Object} data (optional) - overlay some values
8317 * @return {Roo.data.Record} record created.
8319 newRow : function(d) {
8321 this.recordType.prototype.fields.each(function(c) {
8323 case 'int' : da[c.name] = 0; break;
8324 case 'date' : da[c.name] = new Date(); break;
8325 case 'float' : da[c.name] = 0.0; break;
8326 case 'boolean' : da[c.name] = false; break;
8327 default : da[c.name] = ""; break;
8331 return new this.recordType(Roo.apply(da, d));
8336 * Ext JS Library 1.1.1
8337 * Copyright(c) 2006-2007, Ext JS, LLC.
8339 * Originally Released Under LGPL - original licence link has changed is not relivant.
8342 * <script type="text/javascript">
8346 * @class Roo.data.DataProxy
8347 * @extends Roo.data.Observable
8348 * This class is an abstract base class for implementations which provide retrieval of
8349 * unformatted data objects.<br>
8351 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
8352 * (of the appropriate type which knows how to parse the data object) to provide a block of
8353 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
8355 * Custom implementations must implement the load method as described in
8356 * {@link Roo.data.HttpProxy#load}.
8358 Roo.data.DataProxy = function(){
8362 * Fires before a network request is made to retrieve a data object.
8363 * @param {Object} This DataProxy object.
8364 * @param {Object} params The params parameter to the load function.
8369 * Fires before the load method's callback is called.
8370 * @param {Object} This DataProxy object.
8371 * @param {Object} o The data object.
8372 * @param {Object} arg The callback argument object passed to the load function.
8376 * @event loadexception
8377 * Fires if an Exception occurs during data retrieval.
8378 * @param {Object} This DataProxy object.
8379 * @param {Object} o The data object.
8380 * @param {Object} arg The callback argument object passed to the load function.
8381 * @param {Object} e The Exception.
8383 loadexception : true
8385 Roo.data.DataProxy.superclass.constructor.call(this);
8388 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
8391 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
8395 * Ext JS Library 1.1.1
8396 * Copyright(c) 2006-2007, Ext JS, LLC.
8398 * Originally Released Under LGPL - original licence link has changed is not relivant.
8401 * <script type="text/javascript">
8404 * @class Roo.data.MemoryProxy
8405 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
8406 * to the Reader when its load method is called.
8408 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
8410 Roo.data.MemoryProxy = function(data){
8414 Roo.data.MemoryProxy.superclass.constructor.call(this);
8418 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
8420 * Load data from the requested source (in this case an in-memory
8421 * data object passed to the constructor), read the data object into
8422 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
8423 * process that block using the passed callback.
8424 * @param {Object} params This parameter is not used by the MemoryProxy class.
8425 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8426 * object into a block of Roo.data.Records.
8427 * @param {Function} callback The function into which to pass the block of Roo.data.records.
8428 * The function must be passed <ul>
8429 * <li>The Record block object</li>
8430 * <li>The "arg" argument from the load function</li>
8431 * <li>A boolean success indicator</li>
8433 * @param {Object} scope The scope in which to call the callback
8434 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8436 load : function(params, reader, callback, scope, arg){
8437 params = params || {};
8440 result = reader.readRecords(this.data);
8442 this.fireEvent("loadexception", this, arg, null, e);
8443 callback.call(scope, null, arg, false);
8446 callback.call(scope, result, arg, true);
8450 update : function(params, records){
8455 * Ext JS Library 1.1.1
8456 * Copyright(c) 2006-2007, Ext JS, LLC.
8458 * Originally Released Under LGPL - original licence link has changed is not relivant.
8461 * <script type="text/javascript">
8464 * @class Roo.data.HttpProxy
8465 * @extends Roo.data.DataProxy
8466 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
8467 * configured to reference a certain URL.<br><br>
8469 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
8470 * from which the running page was served.<br><br>
8472 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
8474 * Be aware that to enable the browser to parse an XML document, the server must set
8475 * the Content-Type header in the HTTP response to "text/xml".
8477 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
8478 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
8479 * will be used to make the request.
8481 Roo.data.HttpProxy = function(conn){
8482 Roo.data.HttpProxy.superclass.constructor.call(this);
8483 // is conn a conn config or a real conn?
8485 this.useAjax = !conn || !conn.events;
8489 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
8490 // thse are take from connection...
8493 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
8496 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
8497 * extra parameters to each request made by this object. (defaults to undefined)
8500 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
8501 * to each request made by this object. (defaults to undefined)
8504 * @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)
8507 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
8510 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
8516 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
8520 * Return the {@link Roo.data.Connection} object being used by this Proxy.
8521 * @return {Connection} The Connection object. This object may be used to subscribe to events on
8522 * a finer-grained basis than the DataProxy events.
8524 getConnection : function(){
8525 return this.useAjax ? Roo.Ajax : this.conn;
8529 * Load data from the configured {@link Roo.data.Connection}, read the data object into
8530 * a block of Roo.data.Records using the passed {@link 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 params : params || {},
8550 callback : callback,
8555 callback : this.loadResponse,
8559 Roo.applyIf(o, this.conn);
8560 if(this.activeRequest){
8561 Roo.Ajax.abort(this.activeRequest);
8563 this.activeRequest = Roo.Ajax.request(o);
8565 this.conn.request(o);
8568 callback.call(scope||this, null, arg, false);
8573 loadResponse : function(o, success, response){
8574 delete this.activeRequest;
8576 this.fireEvent("loadexception", this, o, response);
8577 o.request.callback.call(o.request.scope, null, o.request.arg, false);
8582 result = o.reader.read(response);
8584 this.fireEvent("loadexception", this, o, response, e);
8585 o.request.callback.call(o.request.scope, null, o.request.arg, false);
8589 this.fireEvent("load", this, o, o.request.arg);
8590 o.request.callback.call(o.request.scope, result, o.request.arg, true);
8594 update : function(dataSet){
8599 updateResponse : function(dataSet){
8604 * Ext JS Library 1.1.1
8605 * Copyright(c) 2006-2007, Ext JS, LLC.
8607 * Originally Released Under LGPL - original licence link has changed is not relivant.
8610 * <script type="text/javascript">
8614 * @class Roo.data.ScriptTagProxy
8615 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
8616 * other than the originating domain of the running page.<br><br>
8618 * <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
8619 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
8621 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
8622 * source code that is used as the source inside a <script> tag.<br><br>
8624 * In order for the browser to process the returned data, the server must wrap the data object
8625 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
8626 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
8627 * depending on whether the callback name was passed:
8630 boolean scriptTag = false;
8631 String cb = request.getParameter("callback");
8634 response.setContentType("text/javascript");
8636 response.setContentType("application/x-json");
8638 Writer out = response.getWriter();
8640 out.write(cb + "(");
8642 out.print(dataBlock.toJsonString());
8649 * @param {Object} config A configuration object.
8651 Roo.data.ScriptTagProxy = function(config){
8652 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
8653 Roo.apply(this, config);
8654 this.head = document.getElementsByTagName("head")[0];
8657 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
8659 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
8661 * @cfg {String} url The URL from which to request the data object.
8664 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
8668 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
8669 * the server the name of the callback function set up by the load call to process the returned data object.
8670 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
8671 * javascript output which calls this named function passing the data object as its only parameter.
8673 callbackParam : "callback",
8675 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
8676 * name to the request.
8681 * Load data from the configured URL, read the data object into
8682 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
8683 * process that block using the passed callback.
8684 * @param {Object} params An object containing properties which are to be used as HTTP parameters
8685 * for the request to the remote server.
8686 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8687 * object into a block of Roo.data.Records.
8688 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
8689 * The function must be passed <ul>
8690 * <li>The Record block object</li>
8691 * <li>The "arg" argument from the load function</li>
8692 * <li>A boolean success indicator</li>
8694 * @param {Object} scope The scope in which to call the callback
8695 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8697 load : function(params, reader, callback, scope, arg){
8698 if(this.fireEvent("beforeload", this, params) !== false){
8700 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
8703 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
8705 url += "&_dc=" + (new Date().getTime());
8707 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
8710 cb : "stcCallback"+transId,
8711 scriptId : "stcScript"+transId,
8715 callback : callback,
8721 window[trans.cb] = function(o){
8722 conn.handleResponse(o, trans);
8725 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
8727 if(this.autoAbort !== false){
8731 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
8733 var script = document.createElement("script");
8734 script.setAttribute("src", url);
8735 script.setAttribute("type", "text/javascript");
8736 script.setAttribute("id", trans.scriptId);
8737 this.head.appendChild(script);
8741 callback.call(scope||this, null, arg, false);
8746 isLoading : function(){
8747 return this.trans ? true : false;
8751 * Abort the current server request.
8754 if(this.isLoading()){
8755 this.destroyTrans(this.trans);
8760 destroyTrans : function(trans, isLoaded){
8761 this.head.removeChild(document.getElementById(trans.scriptId));
8762 clearTimeout(trans.timeoutId);
8764 window[trans.cb] = undefined;
8766 delete window[trans.cb];
8769 // if hasn't been loaded, wait for load to remove it to prevent script error
8770 window[trans.cb] = function(){
8771 window[trans.cb] = undefined;
8773 delete window[trans.cb];
8780 handleResponse : function(o, trans){
8782 this.destroyTrans(trans, true);
8785 result = trans.reader.readRecords(o);
8787 this.fireEvent("loadexception", this, o, trans.arg, e);
8788 trans.callback.call(trans.scope||window, null, trans.arg, false);
8791 this.fireEvent("load", this, o, trans.arg);
8792 trans.callback.call(trans.scope||window, result, trans.arg, true);
8796 handleFailure : function(trans){
8798 this.destroyTrans(trans, false);
8799 this.fireEvent("loadexception", this, null, trans.arg);
8800 trans.callback.call(trans.scope||window, null, trans.arg, false);
8804 * Ext JS Library 1.1.1
8805 * Copyright(c) 2006-2007, Ext JS, LLC.
8807 * Originally Released Under LGPL - original licence link has changed is not relivant.
8810 * <script type="text/javascript">
8814 * @class Roo.data.JsonReader
8815 * @extends Roo.data.DataReader
8816 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
8817 * based on mappings in a provided Roo.data.Record constructor.
8819 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
8820 * in the reply previously.
8825 var RecordDef = Roo.data.Record.create([
8826 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
8827 {name: 'occupation'} // This field will use "occupation" as the mapping.
8829 var myReader = new Roo.data.JsonReader({
8830 totalProperty: "results", // The property which contains the total dataset size (optional)
8831 root: "rows", // The property which contains an Array of row objects
8832 id: "id" // The property within each row object that provides an ID for the record (optional)
8836 * This would consume a JSON file like this:
8838 { 'results': 2, 'rows': [
8839 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
8840 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
8843 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
8844 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
8845 * paged from the remote server.
8846 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
8847 * @cfg {String} root name of the property which contains the Array of row objects.
8848 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
8850 * Create a new JsonReader
8851 * @param {Object} meta Metadata configuration options
8852 * @param {Object} recordType Either an Array of field definition objects,
8853 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
8855 Roo.data.JsonReader = function(meta, recordType){
8858 // set some defaults:
8860 totalProperty: 'total',
8861 successProperty : 'success',
8866 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
8868 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
8871 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
8872 * Used by Store query builder to append _requestMeta to params.
8875 metaFromRemote : false,
8877 * This method is only used by a DataProxy which has retrieved data from a remote server.
8878 * @param {Object} response The XHR object which contains the JSON data in its responseText.
8879 * @return {Object} data A data block which is used by an Roo.data.Store object as
8880 * a cache of Roo.data.Records.
8882 read : function(response){
8883 var json = response.responseText;
8885 var o = /* eval:var:o */ eval("("+json+")");
8887 throw {message: "JsonReader.read: Json object not found"};
8893 this.metaFromRemote = true;
8894 this.meta = o.metaData;
8895 this.recordType = Roo.data.Record.create(o.metaData.fields);
8896 this.onMetaChange(this.meta, this.recordType, o);
8898 return this.readRecords(o);
8901 // private function a store will implement
8902 onMetaChange : function(meta, recordType, o){
8909 simpleAccess: function(obj, subsc) {
8916 getJsonAccessor: function(){
8918 return function(expr) {
8920 return(re.test(expr))
8921 ? new Function("obj", "return obj." + expr)
8931 * Create a data block containing Roo.data.Records from an XML document.
8932 * @param {Object} o An object which contains an Array of row objects in the property specified
8933 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
8934 * which contains the total size of the dataset.
8935 * @return {Object} data A data block which is used by an Roo.data.Store object as
8936 * a cache of Roo.data.Records.
8938 readRecords : function(o){
8940 * After any data loads, the raw JSON data is available for further custom processing.
8944 var s = this.meta, Record = this.recordType,
8945 f = Record.prototype.fields, fi = f.items, fl = f.length;
8947 // Generate extraction functions for the totalProperty, the root, the id, and for each field
8949 if(s.totalProperty) {
8950 this.getTotal = this.getJsonAccessor(s.totalProperty);
8952 if(s.successProperty) {
8953 this.getSuccess = this.getJsonAccessor(s.successProperty);
8955 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
8957 var g = this.getJsonAccessor(s.id);
8958 this.getId = function(rec) {
8960 return (r === undefined || r === "") ? null : r;
8963 this.getId = function(){return null;};
8966 for(var jj = 0; jj < fl; jj++){
8968 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
8969 this.ef[jj] = this.getJsonAccessor(map);
8973 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
8974 if(s.totalProperty){
8975 var vt = parseInt(this.getTotal(o), 10);
8980 if(s.successProperty){
8981 var vs = this.getSuccess(o);
8982 if(vs === false || vs === 'false'){
8987 for(var i = 0; i < c; i++){
8990 var id = this.getId(n);
8991 for(var j = 0; j < fl; j++){
8993 var v = this.ef[j](n);
8995 Roo.log('missing convert for ' + f.name);
8999 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
9001 var record = new Record(values, id);
9003 records[i] = record;
9009 totalRecords : totalRecords
9014 * Ext JS Library 1.1.1
9015 * Copyright(c) 2006-2007, Ext JS, LLC.
9017 * Originally Released Under LGPL - original licence link has changed is not relivant.
9020 * <script type="text/javascript">
9024 * @class Roo.data.ArrayReader
9025 * @extends Roo.data.DataReader
9026 * Data reader class to create an Array of Roo.data.Record objects from an Array.
9027 * Each element of that Array represents a row of data fields. The
9028 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
9029 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
9033 var RecordDef = Roo.data.Record.create([
9034 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
9035 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
9037 var myReader = new Roo.data.ArrayReader({
9038 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
9042 * This would consume an Array like this:
9044 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
9046 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
9048 * Create a new JsonReader
9049 * @param {Object} meta Metadata configuration options.
9050 * @param {Object} recordType Either an Array of field definition objects
9051 * as specified to {@link Roo.data.Record#create},
9052 * or an {@link Roo.data.Record} object
9053 * created using {@link Roo.data.Record#create}.
9055 Roo.data.ArrayReader = function(meta, recordType){
9056 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
9059 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
9061 * Create a data block containing Roo.data.Records from an XML document.
9062 * @param {Object} o An Array of row objects which represents the dataset.
9063 * @return {Object} data A data block which is used by an Roo.data.Store object as
9064 * a cache of Roo.data.Records.
9066 readRecords : function(o){
9067 var sid = this.meta ? this.meta.id : null;
9068 var recordType = this.recordType, fields = recordType.prototype.fields;
9071 for(var i = 0; i < root.length; i++){
9074 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
9075 for(var j = 0, jlen = fields.length; j < jlen; j++){
9076 var f = fields.items[j];
9077 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
9078 var v = n[k] !== undefined ? n[k] : f.defaultValue;
9082 var record = new recordType(values, id);
9084 records[records.length] = record;
9088 totalRecords : records.length
9097 * @class Roo.bootstrap.ComboBox
9098 * @extends Roo.bootstrap.TriggerField
9099 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
9100 * @cfg {Boolean} append (true|false) default false
9102 * Create a new ComboBox.
9103 * @param {Object} config Configuration options
9105 Roo.bootstrap.ComboBox = function(config){
9106 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
9110 * Fires when the dropdown list is expanded
9111 * @param {Roo.bootstrap.ComboBox} combo This combo box
9116 * Fires when the dropdown list is collapsed
9117 * @param {Roo.bootstrap.ComboBox} combo This combo box
9121 * @event beforeselect
9122 * Fires before a list item is selected. Return false to cancel the selection.
9123 * @param {Roo.bootstrap.ComboBox} combo This combo box
9124 * @param {Roo.data.Record} record The data record returned from the underlying store
9125 * @param {Number} index The index of the selected item in the dropdown list
9127 'beforeselect' : true,
9130 * Fires when a list item is selected
9131 * @param {Roo.bootstrap.ComboBox} combo This combo box
9132 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
9133 * @param {Number} index The index of the selected item in the dropdown list
9137 * @event beforequery
9138 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
9139 * The event object passed has these properties:
9140 * @param {Roo.bootstrap.ComboBox} combo This combo box
9141 * @param {String} query The query
9142 * @param {Boolean} forceAll true to force "all" query
9143 * @param {Boolean} cancel true to cancel the query
9144 * @param {Object} e The query event object
9146 'beforequery': true,
9149 * Fires when the 'add' icon is pressed (add a listener to enable add button)
9150 * @param {Roo.bootstrap.ComboBox} combo This combo box
9155 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
9156 * @param {Roo.bootstrap.ComboBox} combo This combo box
9157 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
9162 * Fires when the remove value from the combobox array
9163 * @param {Roo.bootstrap.ComboBox} combo This combo box
9170 this.selectedIndex = -1;
9171 if(this.mode == 'local'){
9172 if(config.queryDelay === undefined){
9173 this.queryDelay = 10;
9175 if(config.minChars === undefined){
9181 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
9184 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
9185 * rendering into an Roo.Editor, defaults to false)
9188 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
9189 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
9192 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
9195 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
9196 * the dropdown list (defaults to undefined, with no header element)
9200 * @cfg {String/Roo.Template} tpl The template to use to render the output
9204 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
9206 listWidth: undefined,
9208 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
9209 * mode = 'remote' or 'text' if mode = 'local')
9211 displayField: undefined,
9213 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
9214 * mode = 'remote' or 'value' if mode = 'local').
9215 * Note: use of a valueField requires the user make a selection
9216 * in order for a value to be mapped.
9218 valueField: undefined,
9222 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
9223 * field's data value (defaults to the underlying DOM element's name)
9225 hiddenName: undefined,
9227 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
9231 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
9233 selectedClass: 'active',
9236 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
9240 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
9241 * anchor positions (defaults to 'tl-bl')
9243 listAlign: 'tl-bl?',
9245 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
9249 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
9250 * query specified by the allQuery config option (defaults to 'query')
9252 triggerAction: 'query',
9254 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
9255 * (defaults to 4, does not apply if editable = false)
9259 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
9260 * delay (typeAheadDelay) if it matches a known value (defaults to false)
9264 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
9265 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
9269 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
9270 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
9274 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
9275 * when editable = true (defaults to false)
9277 selectOnFocus:false,
9279 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
9281 queryParam: 'query',
9283 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
9284 * when mode = 'remote' (defaults to 'Loading...')
9286 loadingText: 'Loading...',
9288 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
9292 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
9296 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
9297 * traditional select (defaults to true)
9301 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
9305 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
9309 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
9310 * listWidth has a higher value)
9314 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
9315 * allow the user to set arbitrary text into the field (defaults to false)
9317 forceSelection:false,
9319 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
9320 * if typeAhead = true (defaults to 250)
9322 typeAheadDelay : 250,
9324 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
9325 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
9327 valueNotFoundText : undefined,
9329 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
9334 * @cfg {Boolean} disableClear Disable showing of clear button.
9336 disableClear : false,
9338 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
9340 alwaysQuery : false,
9343 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
9357 // element that contains real text value.. (when hidden is used..)
9360 initEvents: function(){
9363 throw "can not find store for combo";
9365 this.store = Roo.factory(this.store, Roo.data);
9369 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
9372 if(this.hiddenName){
9374 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
9376 this.hiddenField.dom.value =
9377 this.hiddenValue !== undefined ? this.hiddenValue :
9378 this.value !== undefined ? this.value : '';
9380 // prevent input submission
9381 this.el.dom.removeAttribute('name');
9382 this.hiddenField.dom.setAttribute('name', this.hiddenName);
9387 // this.el.dom.setAttribute('autocomplete', 'off');
9390 var cls = 'x-combo-list';
9391 this.list = this.el.select('ul.dropdown-menu',true).first();
9393 //this.list = new Roo.Layer({
9394 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
9397 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
9398 this.list.setWidth(lw);
9400 this.list.on('mouseover', this.onViewOver, this);
9401 this.list.on('mousemove', this.onViewMove, this);
9403 this.list.on('scroll', this.onViewScroll, this);
9406 this.list.swallowEvent('mousewheel');
9407 this.assetHeight = 0;
9410 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
9411 this.assetHeight += this.header.getHeight();
9414 this.innerList = this.list.createChild({cls:cls+'-inner'});
9415 this.innerList.on('mouseover', this.onViewOver, this);
9416 this.innerList.on('mousemove', this.onViewMove, this);
9417 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
9419 if(this.allowBlank && !this.pageSize && !this.disableClear){
9420 this.footer = this.list.createChild({cls:cls+'-ft'});
9421 this.pageTb = new Roo.Toolbar(this.footer);
9425 this.footer = this.list.createChild({cls:cls+'-ft'});
9426 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
9427 {pageSize: this.pageSize});
9431 if (this.pageTb && this.allowBlank && !this.disableClear) {
9433 this.pageTb.add(new Roo.Toolbar.Fill(), {
9434 cls: 'x-btn-icon x-btn-clear',
9440 _this.onSelect(false, -1);
9445 this.assetHeight += this.footer.getHeight();
9450 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
9453 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
9454 singleSelect:true, store: this.store, selectedClass: this.selectedClass
9456 //this.view.wrapEl.setDisplayed(false);
9457 this.view.on('click', this.onViewClick, this);
9461 this.store.on('beforeload', this.onBeforeLoad, this);
9462 this.store.on('load', this.onLoad, this);
9463 this.store.on('loadexception', this.onLoadException, this);
9466 this.resizer = new Roo.Resizable(this.list, {
9467 pinned:true, handles:'se'
9469 this.resizer.on('resize', function(r, w, h){
9470 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
9472 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
9473 this.restrictHeight();
9475 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
9479 this.editable = true;
9480 this.setEditable(false);
9485 if (typeof(this.events.add.listeners) != 'undefined') {
9487 this.addicon = this.wrap.createChild(
9488 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
9490 this.addicon.on('click', function(e) {
9491 this.fireEvent('add', this);
9494 if (typeof(this.events.edit.listeners) != 'undefined') {
9496 this.editicon = this.wrap.createChild(
9497 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
9499 this.editicon.setStyle('margin-left', '40px');
9501 this.editicon.on('click', function(e) {
9503 // we fire even if inothing is selected..
9504 this.fireEvent('edit', this, this.lastData );
9510 this.keyNav = new Roo.KeyNav(this.inputEl(), {
9512 this.inKeyMode = true;
9516 "down" : function(e){
9517 if(!this.isExpanded()){
9518 this.onTriggerClick();
9520 this.inKeyMode = true;
9525 "enter" : function(e){
9530 "esc" : function(e){
9534 "tab" : function(e){
9537 if(this.fireEvent("specialkey", this, e)){
9538 this.onViewClick(false);
9546 doRelay : function(foo, bar, hname){
9547 if(hname == 'down' || this.scope.isExpanded()){
9548 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
9557 this.queryDelay = Math.max(this.queryDelay || 10,
9558 this.mode == 'local' ? 10 : 250);
9561 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
9564 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
9566 if(this.editable !== false){
9567 this.inputEl().on("keyup", this.onKeyUp, this);
9569 if(this.forceSelection){
9570 this.inputEl().on('blur', this.doForce, this);
9574 this.choices = this.el.select('ul.select2-choices', true).first();
9575 this.searchField = this.el.select('ul li.select2-search-field', true).first();
9579 onDestroy : function(){
9581 this.view.setStore(null);
9582 this.view.el.removeAllListeners();
9583 this.view.el.remove();
9584 this.view.purgeListeners();
9587 this.list.dom.innerHTML = '';
9590 this.store.un('beforeload', this.onBeforeLoad, this);
9591 this.store.un('load', this.onLoad, this);
9592 this.store.un('loadexception', this.onLoadException, this);
9594 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
9598 fireKey : function(e){
9599 if(e.isNavKeyPress() && !this.list.isVisible()){
9600 this.fireEvent("specialkey", this, e);
9605 onResize: function(w, h){
9606 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
9608 // if(typeof w != 'number'){
9609 // // we do not handle it!?!?
9612 // var tw = this.trigger.getWidth();
9613 // // tw += this.addicon ? this.addicon.getWidth() : 0;
9614 // // tw += this.editicon ? this.editicon.getWidth() : 0;
9616 // this.inputEl().setWidth( this.adjustWidth('input', x));
9618 // //this.trigger.setStyle('left', x+'px');
9620 // if(this.list && this.listWidth === undefined){
9621 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
9622 // this.list.setWidth(lw);
9623 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
9631 * Allow or prevent the user from directly editing the field text. If false is passed,
9632 * the user will only be able to select from the items defined in the dropdown list. This method
9633 * is the runtime equivalent of setting the 'editable' config option at config time.
9634 * @param {Boolean} value True to allow the user to directly edit the field text
9636 setEditable : function(value){
9637 if(value == this.editable){
9640 this.editable = value;
9642 this.inputEl().dom.setAttribute('readOnly', true);
9643 this.inputEl().on('mousedown', this.onTriggerClick, this);
9644 this.inputEl().addClass('x-combo-noedit');
9646 this.inputEl().dom.setAttribute('readOnly', false);
9647 this.inputEl().un('mousedown', this.onTriggerClick, this);
9648 this.inputEl().removeClass('x-combo-noedit');
9654 onBeforeLoad : function(combo,opts){
9659 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
9661 this.restrictHeight();
9662 this.selectedIndex = -1;
9666 onLoad : function(){
9668 this.hasQuery = false;
9674 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
9675 this.loading.hide();
9678 if(this.store.getCount() > 0){
9680 this.restrictHeight();
9681 if(this.lastQuery == this.allQuery){
9683 this.inputEl().dom.select();
9685 if(!this.selectByValue(this.value, true)){
9686 this.select(0, true);
9690 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
9691 this.taTask.delay(this.typeAheadDelay);
9695 this.onEmptyResults();
9701 onLoadException : function()
9703 this.hasQuery = false;
9705 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
9706 this.loading.hide();
9710 Roo.log(this.store.reader.jsonData);
9711 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
9713 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
9719 onTypeAhead : function(){
9720 if(this.store.getCount() > 0){
9721 var r = this.store.getAt(0);
9722 var newValue = r.data[this.displayField];
9723 var len = newValue.length;
9724 var selStart = this.getRawValue().length;
9726 if(selStart != len){
9727 this.setRawValue(newValue);
9728 this.selectText(selStart, newValue.length);
9734 onSelect : function(record, index){
9736 if(this.fireEvent('beforeselect', this, record, index) !== false){
9738 this.setFromData(index > -1 ? record.data : false);
9741 this.fireEvent('select', this, record, index);
9746 * Returns the currently selected field value or empty string if no value is set.
9747 * @return {String} value The selected value
9749 getValue : function(){
9752 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
9755 if(this.valueField){
9756 return typeof this.value != 'undefined' ? this.value : '';
9758 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
9763 * Clears any text/value currently set in the field
9765 clearValue : function(){
9766 if(this.hiddenField){
9767 this.hiddenField.dom.value = '';
9770 this.setRawValue('');
9771 this.lastSelectionText = '';
9776 * Sets the specified value into the field. If the value finds a match, the corresponding record text
9777 * will be displayed in the field. If the value does not match the data value of an existing item,
9778 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
9779 * Otherwise the field will be blank (although the value will still be set).
9780 * @param {String} value The value to match
9782 setValue : function(v){
9789 if(this.valueField){
9790 var r = this.findRecord(this.valueField, v);
9792 text = r.data[this.displayField];
9793 }else if(this.valueNotFoundText !== undefined){
9794 text = this.valueNotFoundText;
9797 this.lastSelectionText = text;
9798 if(this.hiddenField){
9799 this.hiddenField.dom.value = v;
9801 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
9805 * @property {Object} the last set data for the element
9810 * Sets the value of the field based on a object which is related to the record format for the store.
9811 * @param {Object} value the value to set as. or false on reset?
9813 setFromData : function(o){
9820 var dv = ''; // display value
9821 var vv = ''; // value value..
9823 if (this.displayField) {
9824 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
9826 // this is an error condition!!!
9827 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
9830 if(this.valueField){
9831 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
9834 if(this.hiddenField){
9835 this.hiddenField.dom.value = vv;
9837 this.lastSelectionText = dv;
9838 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
9842 // no hidden field.. - we store the value in 'value', but still display
9843 // display field!!!!
9844 this.lastSelectionText = dv;
9845 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
9852 // overridden so that last data is reset..
9853 this.setValue(this.originalValue);
9854 this.clearInvalid();
9855 this.lastData = false;
9857 this.view.clearSelections();
9861 findRecord : function(prop, value){
9863 if(this.store.getCount() > 0){
9864 this.store.each(function(r){
9865 if(r.data[prop] == value){
9877 // returns hidden if it's set..
9878 if (!this.rendered) {return ''};
9879 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
9883 onViewMove : function(e, t){
9884 this.inKeyMode = false;
9888 onViewOver : function(e, t){
9889 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
9892 var item = this.view.findItemFromChild(t);
9894 var index = this.view.indexOf(item);
9895 this.select(index, false);
9900 onViewClick : function(doFocus)
9902 var index = this.view.getSelectedIndexes()[0];
9903 var r = this.store.getAt(index);
9905 this.onSelect(r, index);
9907 if(doFocus !== false && !this.blockFocus){
9908 this.inputEl().focus();
9913 restrictHeight : function(){
9914 //this.innerList.dom.style.height = '';
9915 //var inner = this.innerList.dom;
9916 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
9917 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
9918 //this.list.beginUpdate();
9919 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
9920 this.list.alignTo(this.inputEl(), this.listAlign);
9921 //this.list.endUpdate();
9925 onEmptyResults : function(){
9930 * Returns true if the dropdown list is expanded, else false.
9932 isExpanded : function(){
9933 return this.list.isVisible();
9937 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
9938 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
9939 * @param {String} value The data value of the item to select
9940 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
9941 * selected item if it is not currently in view (defaults to true)
9942 * @return {Boolean} True if the value matched an item in the list, else false
9944 selectByValue : function(v, scrollIntoView){
9945 if(v !== undefined && v !== null){
9946 var r = this.findRecord(this.valueField || this.displayField, v);
9948 this.select(this.store.indexOf(r), scrollIntoView);
9956 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
9957 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
9958 * @param {Number} index The zero-based index of the list item to select
9959 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
9960 * selected item if it is not currently in view (defaults to true)
9962 select : function(index, scrollIntoView){
9963 this.selectedIndex = index;
9964 this.view.select(index);
9965 if(scrollIntoView !== false){
9966 var el = this.view.getNode(index);
9968 //this.innerList.scrollChildIntoView(el, false);
9975 selectNext : function(){
9976 var ct = this.store.getCount();
9978 if(this.selectedIndex == -1){
9980 }else if(this.selectedIndex < ct-1){
9981 this.select(this.selectedIndex+1);
9987 selectPrev : function(){
9988 var ct = this.store.getCount();
9990 if(this.selectedIndex == -1){
9992 }else if(this.selectedIndex != 0){
9993 this.select(this.selectedIndex-1);
9999 onKeyUp : function(e){
10000 if(this.editable !== false && !e.isSpecialKey()){
10001 this.lastKey = e.getKey();
10002 this.dqTask.delay(this.queryDelay);
10007 validateBlur : function(){
10008 return !this.list || !this.list.isVisible();
10012 initQuery : function(){
10013 this.doQuery(this.getRawValue());
10017 doForce : function(){
10018 if(this.inputEl().dom.value.length > 0){
10019 this.inputEl().dom.value =
10020 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
10026 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
10027 * query allowing the query action to be canceled if needed.
10028 * @param {String} query The SQL query to execute
10029 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
10030 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
10031 * saved in the current store (defaults to false)
10033 doQuery : function(q, forceAll){
10035 if(q === undefined || q === null){
10040 forceAll: forceAll,
10044 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
10049 forceAll = qe.forceAll;
10050 if(forceAll === true || (q.length >= this.minChars)){
10052 this.hasQuery = true;
10054 if(this.lastQuery != q || this.alwaysQuery){
10055 this.lastQuery = q;
10056 if(this.mode == 'local'){
10057 this.selectedIndex = -1;
10059 this.store.clearFilter();
10061 this.store.filter(this.displayField, q);
10065 this.store.baseParams[this.queryParam] = q;
10067 var options = {params : this.getParams(q)};
10070 options.add = true;
10071 options.params.start = this.page * this.pageSize;
10074 this.store.load(options);
10078 this.selectedIndex = -1;
10083 this.loadNext = false;
10087 getParams : function(q){
10089 //p[this.queryParam] = q;
10093 p.limit = this.pageSize;
10099 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
10101 collapse : function(){
10102 if(!this.isExpanded()){
10107 Roo.get(document).un('mousedown', this.collapseIf, this);
10108 Roo.get(document).un('mousewheel', this.collapseIf, this);
10109 if (!this.editable) {
10110 Roo.get(document).un('keydown', this.listKeyPress, this);
10112 this.fireEvent('collapse', this);
10116 collapseIf : function(e){
10117 var in_combo = e.within(this.el);
10118 var in_list = e.within(this.list);
10120 if (in_combo || in_list) {
10121 //e.stopPropagation();
10130 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
10132 expand : function(){
10134 if(this.isExpanded() || !this.hasFocus){
10138 this.list.alignTo(this.inputEl(), this.listAlign);
10140 Roo.get(document).on('mousedown', this.collapseIf, this);
10141 Roo.get(document).on('mousewheel', this.collapseIf, this);
10142 if (!this.editable) {
10143 Roo.get(document).on('keydown', this.listKeyPress, this);
10146 this.fireEvent('expand', this);
10150 // Implements the default empty TriggerField.onTriggerClick function
10151 onTriggerClick : function()
10153 Roo.log('trigger click');
10160 this.loadNext = false;
10162 if(this.isExpanded()){
10164 if (!this.blockFocus) {
10165 this.inputEl().focus();
10169 this.hasFocus = true;
10170 if(this.triggerAction == 'all') {
10171 this.doQuery(this.allQuery, true);
10173 this.doQuery(this.getRawValue());
10175 if (!this.blockFocus) {
10176 this.inputEl().focus();
10180 listKeyPress : function(e)
10182 //Roo.log('listkeypress');
10183 // scroll to first matching element based on key pres..
10184 if (e.isSpecialKey()) {
10187 var k = String.fromCharCode(e.getKey()).toUpperCase();
10190 var csel = this.view.getSelectedNodes();
10191 var cselitem = false;
10193 var ix = this.view.indexOf(csel[0]);
10194 cselitem = this.store.getAt(ix);
10195 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
10201 this.store.each(function(v) {
10203 // start at existing selection.
10204 if (cselitem.id == v.id) {
10210 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
10211 match = this.store.indexOf(v);
10217 if (match === false) {
10218 return true; // no more action?
10221 this.view.select(match);
10222 var sn = Roo.get(this.view.getSelectedNodes()[0])
10223 //sn.scrollIntoView(sn.dom.parentNode, false);
10226 onViewScroll : function(e, t){
10228 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
10232 this.hasQuery = true;
10234 this.loading = this.list.select('.loading', true).first();
10236 if(this.loading === null){
10237 this.list.createChild({
10239 cls: 'loading select2-more-results select2-active',
10240 html: 'Loading more results...'
10243 this.loading = this.list.select('.loading', true).first();
10245 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
10247 this.loading.hide();
10250 this.loading.show();
10255 this.loadNext = true;
10257 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
10262 addItem : function(o)
10264 var dv = ''; // display value
10266 if (this.displayField) {
10267 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
10269 // this is an error condition!!!
10270 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
10277 var choice = this.choices.createChild({
10279 cls: 'select2-search-choice',
10288 cls: 'select2-search-choice-close',
10293 }, this.searchField);
10295 var close = choice.select('a.select2-search-choice-close', true).first()
10297 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
10304 this.inputEl().dom.value = '';
10308 onRemoveItem : function(e, _self, o)
10310 e.preventDefault();
10311 var index = this.item.indexOf(o.data) * 1;
10314 Roo.log('not this item?!');
10318 this.item.splice(index, 1);
10323 this.fireEvent('remove', this, e);
10327 syncValue : function()
10329 if(!this.item.length){
10336 Roo.each(this.item, function(i){
10337 if(_this.valueField){
10338 value.push(i[_this.valueField]);
10345 this.value = value.join(',');
10347 if(this.hiddenField){
10348 this.hiddenField.dom.value = this.value;
10352 clearItem : function()
10354 if(!this.multiple){
10360 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
10370 * @cfg {Boolean} grow
10374 * @cfg {Number} growMin
10378 * @cfg {Number} growMax
10388 * Ext JS Library 1.1.1
10389 * Copyright(c) 2006-2007, Ext JS, LLC.
10391 * Originally Released Under LGPL - original licence link has changed is not relivant.
10394 * <script type="text/javascript">
10399 * @extends Roo.util.Observable
10400 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
10401 * This class also supports single and multi selection modes. <br>
10402 * Create a data model bound view:
10404 var store = new Roo.data.Store(...);
10406 var view = new Roo.View({
10408 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
10410 singleSelect: true,
10411 selectedClass: "ydataview-selected",
10415 // listen for node click?
10416 view.on("click", function(vw, index, node, e){
10417 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
10421 dataModel.load("foobar.xml");
10423 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
10425 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
10426 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
10428 * Note: old style constructor is still suported (container, template, config)
10431 * Create a new View
10432 * @param {Object} config The config object
10435 Roo.View = function(config, depreciated_tpl, depreciated_config){
10437 if (typeof(depreciated_tpl) == 'undefined') {
10438 // new way.. - universal constructor.
10439 Roo.apply(this, config);
10440 this.el = Roo.get(this.el);
10443 this.el = Roo.get(config);
10444 this.tpl = depreciated_tpl;
10445 Roo.apply(this, depreciated_config);
10447 this.wrapEl = this.el.wrap().wrap();
10448 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
10451 if(typeof(this.tpl) == "string"){
10452 this.tpl = new Roo.Template(this.tpl);
10454 // support xtype ctors..
10455 this.tpl = new Roo.factory(this.tpl, Roo);
10459 this.tpl.compile();
10467 * @event beforeclick
10468 * Fires before a click is processed. Returns false to cancel the default action.
10469 * @param {Roo.View} this
10470 * @param {Number} index The index of the target node
10471 * @param {HTMLElement} node The target node
10472 * @param {Roo.EventObject} e The raw event object
10474 "beforeclick" : true,
10477 * Fires when a template node is clicked.
10478 * @param {Roo.View} this
10479 * @param {Number} index The index of the target node
10480 * @param {HTMLElement} node The target node
10481 * @param {Roo.EventObject} e The raw event object
10486 * Fires when a template node is double clicked.
10487 * @param {Roo.View} this
10488 * @param {Number} index The index of the target node
10489 * @param {HTMLElement} node The target node
10490 * @param {Roo.EventObject} e The raw event object
10494 * @event contextmenu
10495 * Fires when a template node is right clicked.
10496 * @param {Roo.View} this
10497 * @param {Number} index The index of the target node
10498 * @param {HTMLElement} node The target node
10499 * @param {Roo.EventObject} e The raw event object
10501 "contextmenu" : true,
10503 * @event selectionchange
10504 * Fires when the selected nodes change.
10505 * @param {Roo.View} this
10506 * @param {Array} selections Array of the selected nodes
10508 "selectionchange" : true,
10511 * @event beforeselect
10512 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
10513 * @param {Roo.View} this
10514 * @param {HTMLElement} node The node to be selected
10515 * @param {Array} selections Array of currently selected nodes
10517 "beforeselect" : true,
10519 * @event preparedata
10520 * Fires on every row to render, to allow you to change the data.
10521 * @param {Roo.View} this
10522 * @param {Object} data to be rendered (change this)
10524 "preparedata" : true
10532 "click": this.onClick,
10533 "dblclick": this.onDblClick,
10534 "contextmenu": this.onContextMenu,
10538 this.selections = [];
10540 this.cmp = new Roo.CompositeElementLite([]);
10542 this.store = Roo.factory(this.store, Roo.data);
10543 this.setStore(this.store, true);
10546 if ( this.footer && this.footer.xtype) {
10548 var fctr = this.wrapEl.appendChild(document.createElement("div"));
10550 this.footer.dataSource = this.store
10551 this.footer.container = fctr;
10552 this.footer = Roo.factory(this.footer, Roo);
10553 fctr.insertFirst(this.el);
10555 // this is a bit insane - as the paging toolbar seems to detach the el..
10556 // dom.parentNode.parentNode.parentNode
10557 // they get detached?
10561 Roo.View.superclass.constructor.call(this);
10566 Roo.extend(Roo.View, Roo.util.Observable, {
10569 * @cfg {Roo.data.Store} store Data store to load data from.
10574 * @cfg {String|Roo.Element} el The container element.
10579 * @cfg {String|Roo.Template} tpl The template used by this View
10583 * @cfg {String} dataName the named area of the template to use as the data area
10584 * Works with domtemplates roo-name="name"
10588 * @cfg {String} selectedClass The css class to add to selected nodes
10590 selectedClass : "x-view-selected",
10592 * @cfg {String} emptyText The empty text to show when nothing is loaded.
10597 * @cfg {String} text to display on mask (default Loading)
10601 * @cfg {Boolean} multiSelect Allow multiple selection
10603 multiSelect : false,
10605 * @cfg {Boolean} singleSelect Allow single selection
10607 singleSelect: false,
10610 * @cfg {Boolean} toggleSelect - selecting
10612 toggleSelect : false,
10615 * Returns the element this view is bound to.
10616 * @return {Roo.Element}
10618 getEl : function(){
10619 return this.wrapEl;
10625 * Refreshes the view. - called by datachanged on the store. - do not call directly.
10627 refresh : function(){
10628 Roo.log('refresh');
10631 // if we are using something like 'domtemplate', then
10632 // the what gets used is:
10633 // t.applySubtemplate(NAME, data, wrapping data..)
10634 // the outer template then get' applied with
10635 // the store 'extra data'
10636 // and the body get's added to the
10637 // roo-name="data" node?
10638 // <span class='roo-tpl-{name}'></span> ?????
10642 this.clearSelections();
10643 this.el.update("");
10645 var records = this.store.getRange();
10646 if(records.length < 1) {
10648 // is this valid?? = should it render a template??
10650 this.el.update(this.emptyText);
10654 if (this.dataName) {
10655 this.el.update(t.apply(this.store.meta)); //????
10656 el = this.el.child('.roo-tpl-' + this.dataName);
10659 for(var i = 0, len = records.length; i < len; i++){
10660 var data = this.prepareData(records[i].data, i, records[i]);
10661 this.fireEvent("preparedata", this, data, i, records[i]);
10662 html[html.length] = Roo.util.Format.trim(
10664 t.applySubtemplate(this.dataName, data, this.store.meta) :
10671 el.update(html.join(""));
10672 this.nodes = el.dom.childNodes;
10673 this.updateIndexes(0);
10678 * Function to override to reformat the data that is sent to
10679 * the template for each node.
10680 * DEPRICATED - use the preparedata event handler.
10681 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
10682 * a JSON object for an UpdateManager bound view).
10684 prepareData : function(data, index, record)
10686 this.fireEvent("preparedata", this, data, index, record);
10690 onUpdate : function(ds, record){
10691 Roo.log('on update');
10692 this.clearSelections();
10693 var index = this.store.indexOf(record);
10694 var n = this.nodes[index];
10695 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
10696 n.parentNode.removeChild(n);
10697 this.updateIndexes(index, index);
10703 onAdd : function(ds, records, index)
10705 Roo.log(['on Add', ds, records, index] );
10706 this.clearSelections();
10707 if(this.nodes.length == 0){
10711 var n = this.nodes[index];
10712 for(var i = 0, len = records.length; i < len; i++){
10713 var d = this.prepareData(records[i].data, i, records[i]);
10715 this.tpl.insertBefore(n, d);
10718 this.tpl.append(this.el, d);
10721 this.updateIndexes(index);
10724 onRemove : function(ds, record, index){
10725 Roo.log('onRemove');
10726 this.clearSelections();
10727 var el = this.dataName ?
10728 this.el.child('.roo-tpl-' + this.dataName) :
10731 el.dom.removeChild(this.nodes[index]);
10732 this.updateIndexes(index);
10736 * Refresh an individual node.
10737 * @param {Number} index
10739 refreshNode : function(index){
10740 this.onUpdate(this.store, this.store.getAt(index));
10743 updateIndexes : function(startIndex, endIndex){
10744 var ns = this.nodes;
10745 startIndex = startIndex || 0;
10746 endIndex = endIndex || ns.length - 1;
10747 for(var i = startIndex; i <= endIndex; i++){
10748 ns[i].nodeIndex = i;
10753 * Changes the data store this view uses and refresh the view.
10754 * @param {Store} store
10756 setStore : function(store, initial){
10757 if(!initial && this.store){
10758 this.store.un("datachanged", this.refresh);
10759 this.store.un("add", this.onAdd);
10760 this.store.un("remove", this.onRemove);
10761 this.store.un("update", this.onUpdate);
10762 this.store.un("clear", this.refresh);
10763 this.store.un("beforeload", this.onBeforeLoad);
10764 this.store.un("load", this.onLoad);
10765 this.store.un("loadexception", this.onLoad);
10769 store.on("datachanged", this.refresh, this);
10770 store.on("add", this.onAdd, this);
10771 store.on("remove", this.onRemove, this);
10772 store.on("update", this.onUpdate, this);
10773 store.on("clear", this.refresh, this);
10774 store.on("beforeload", this.onBeforeLoad, this);
10775 store.on("load", this.onLoad, this);
10776 store.on("loadexception", this.onLoad, this);
10784 * onbeforeLoad - masks the loading area.
10787 onBeforeLoad : function(store,opts)
10789 Roo.log('onBeforeLoad');
10791 this.el.update("");
10793 this.el.mask(this.mask ? this.mask : "Loading" );
10795 onLoad : function ()
10802 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
10803 * @param {HTMLElement} node
10804 * @return {HTMLElement} The template node
10806 findItemFromChild : function(node){
10807 var el = this.dataName ?
10808 this.el.child('.roo-tpl-' + this.dataName,true) :
10811 if(!node || node.parentNode == el){
10814 var p = node.parentNode;
10815 while(p && p != el){
10816 if(p.parentNode == el){
10825 onClick : function(e){
10826 var item = this.findItemFromChild(e.getTarget());
10828 var index = this.indexOf(item);
10829 if(this.onItemClick(item, index, e) !== false){
10830 this.fireEvent("click", this, index, item, e);
10833 this.clearSelections();
10838 onContextMenu : function(e){
10839 var item = this.findItemFromChild(e.getTarget());
10841 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
10846 onDblClick : function(e){
10847 var item = this.findItemFromChild(e.getTarget());
10849 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
10853 onItemClick : function(item, index, e)
10855 if(this.fireEvent("beforeclick", this, index, item, e) === false){
10858 if (this.toggleSelect) {
10859 var m = this.isSelected(item) ? 'unselect' : 'select';
10862 _t[m](item, true, false);
10865 if(this.multiSelect || this.singleSelect){
10866 if(this.multiSelect && e.shiftKey && this.lastSelection){
10867 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
10869 this.select(item, this.multiSelect && e.ctrlKey);
10870 this.lastSelection = item;
10872 e.preventDefault();
10878 * Get the number of selected nodes.
10881 getSelectionCount : function(){
10882 return this.selections.length;
10886 * Get the currently selected nodes.
10887 * @return {Array} An array of HTMLElements
10889 getSelectedNodes : function(){
10890 return this.selections;
10894 * Get the indexes of the selected nodes.
10897 getSelectedIndexes : function(){
10898 var indexes = [], s = this.selections;
10899 for(var i = 0, len = s.length; i < len; i++){
10900 indexes.push(s[i].nodeIndex);
10906 * Clear all selections
10907 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
10909 clearSelections : function(suppressEvent){
10910 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
10911 this.cmp.elements = this.selections;
10912 this.cmp.removeClass(this.selectedClass);
10913 this.selections = [];
10914 if(!suppressEvent){
10915 this.fireEvent("selectionchange", this, this.selections);
10921 * Returns true if the passed node is selected
10922 * @param {HTMLElement/Number} node The node or node index
10923 * @return {Boolean}
10925 isSelected : function(node){
10926 var s = this.selections;
10930 node = this.getNode(node);
10931 return s.indexOf(node) !== -1;
10936 * @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
10937 * @param {Boolean} keepExisting (optional) true to keep existing selections
10938 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
10940 select : function(nodeInfo, keepExisting, suppressEvent){
10941 if(nodeInfo instanceof Array){
10943 this.clearSelections(true);
10945 for(var i = 0, len = nodeInfo.length; i < len; i++){
10946 this.select(nodeInfo[i], true, true);
10950 var node = this.getNode(nodeInfo);
10951 if(!node || this.isSelected(node)){
10952 return; // already selected.
10955 this.clearSelections(true);
10957 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
10958 Roo.fly(node).addClass(this.selectedClass);
10959 this.selections.push(node);
10960 if(!suppressEvent){
10961 this.fireEvent("selectionchange", this, this.selections);
10969 * @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
10970 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
10971 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
10973 unselect : function(nodeInfo, keepExisting, suppressEvent)
10975 if(nodeInfo instanceof Array){
10976 Roo.each(this.selections, function(s) {
10977 this.unselect(s, nodeInfo);
10981 var node = this.getNode(nodeInfo);
10982 if(!node || !this.isSelected(node)){
10983 Roo.log("not selected");
10984 return; // not selected.
10988 Roo.each(this.selections, function(s) {
10990 Roo.fly(node).removeClass(this.selectedClass);
10997 this.selections= ns;
10998 this.fireEvent("selectionchange", this, this.selections);
11002 * Gets a template node.
11003 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
11004 * @return {HTMLElement} The node or null if it wasn't found
11006 getNode : function(nodeInfo){
11007 if(typeof nodeInfo == "string"){
11008 return document.getElementById(nodeInfo);
11009 }else if(typeof nodeInfo == "number"){
11010 return this.nodes[nodeInfo];
11016 * Gets a range template nodes.
11017 * @param {Number} startIndex
11018 * @param {Number} endIndex
11019 * @return {Array} An array of nodes
11021 getNodes : function(start, end){
11022 var ns = this.nodes;
11023 start = start || 0;
11024 end = typeof end == "undefined" ? ns.length - 1 : end;
11027 for(var i = start; i <= end; i++){
11031 for(var i = start; i >= end; i--){
11039 * Finds the index of the passed node
11040 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
11041 * @return {Number} The index of the node or -1
11043 indexOf : function(node){
11044 node = this.getNode(node);
11045 if(typeof node.nodeIndex == "number"){
11046 return node.nodeIndex;
11048 var ns = this.nodes;
11049 for(var i = 0, len = ns.length; i < len; i++){
11060 * based on jquery fullcalendar
11064 Roo.bootstrap = Roo.bootstrap || {};
11066 * @class Roo.bootstrap.Calendar
11067 * @extends Roo.bootstrap.Component
11068 * Bootstrap Calendar class
11069 * @cfg {Boolean} loadMask (true|false) default false
11070 * @cfg {Object} header generate the user specific header of the calendar, default false
11073 * Create a new Container
11074 * @param {Object} config The config object
11079 Roo.bootstrap.Calendar = function(config){
11080 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
11084 * Fires when a date is selected
11085 * @param {DatePicker} this
11086 * @param {Date} date The selected date
11090 * @event monthchange
11091 * Fires when the displayed month changes
11092 * @param {DatePicker} this
11093 * @param {Date} date The selected month
11095 'monthchange': true,
11097 * @event evententer
11098 * Fires when mouse over an event
11099 * @param {Calendar} this
11100 * @param {event} Event
11102 'evententer': true,
11104 * @event eventleave
11105 * Fires when the mouse leaves an
11106 * @param {Calendar} this
11109 'eventleave': true,
11111 * @event eventclick
11112 * Fires when the mouse click an
11113 * @param {Calendar} this
11122 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
11125 * @cfg {Number} startDay
11126 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
11134 getAutoCreate : function(){
11137 var fc_button = function(name, corner, style, content ) {
11138 return Roo.apply({},{
11140 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
11142 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
11145 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
11156 style : 'width:100%',
11163 cls : 'fc-header-left',
11165 fc_button('prev', 'left', 'arrow', '‹' ),
11166 fc_button('next', 'right', 'arrow', '›' ),
11167 { tag: 'span', cls: 'fc-header-space' },
11168 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
11176 cls : 'fc-header-center',
11180 cls: 'fc-header-title',
11183 html : 'month / year'
11191 cls : 'fc-header-right',
11193 /* fc_button('month', 'left', '', 'month' ),
11194 fc_button('week', '', '', 'week' ),
11195 fc_button('day', 'right', '', 'day' )
11207 header = this.header;
11210 var cal_heads = function() {
11212 // fixme - handle this.
11214 for (var i =0; i < Date.dayNames.length; i++) {
11215 var d = Date.dayNames[i];
11218 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
11219 html : d.substring(0,3)
11223 ret[0].cls += ' fc-first';
11224 ret[6].cls += ' fc-last';
11227 var cal_cell = function(n) {
11230 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
11235 cls: 'fc-day-number',
11239 cls: 'fc-day-content',
11243 style: 'position: relative;' // height: 17px;
11255 var cal_rows = function() {
11258 for (var r = 0; r < 6; r++) {
11265 for (var i =0; i < Date.dayNames.length; i++) {
11266 var d = Date.dayNames[i];
11267 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
11270 row.cn[0].cls+=' fc-first';
11271 row.cn[0].cn[0].style = 'min-height:90px';
11272 row.cn[6].cls+=' fc-last';
11276 ret[0].cls += ' fc-first';
11277 ret[4].cls += ' fc-prev-last';
11278 ret[5].cls += ' fc-last';
11285 cls: 'fc-border-separate',
11286 style : 'width:100%',
11294 cls : 'fc-first fc-last',
11312 cls : 'fc-content',
11313 style : "position: relative;",
11316 cls : 'fc-view fc-view-month fc-grid',
11317 style : 'position: relative',
11318 unselectable : 'on',
11321 cls : 'fc-event-container',
11322 style : 'position:absolute;z-index:8;top:0;left:0;'
11340 initEvents : function()
11343 throw "can not find store for calendar";
11349 style: "text-align:center",
11353 style: "background-color:white;width:50%;margin:250 auto",
11357 src: rootURL + '/roojs1/images/ux/lightbox/loading.gif'
11368 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
11370 var size = this.el.select('.fc-content', true).first().getSize();
11371 this.maskEl.setSize(size.width, size.height);
11372 this.maskEl.enableDisplayMode("block");
11373 if(!this.loadMask){
11374 this.maskEl.hide();
11377 this.store = Roo.factory(this.store, Roo.data);
11378 this.store.on('load', this.onLoad, this);
11379 this.store.on('beforeload', this.onBeforeLoad, this);
11383 this.cells = this.el.select('.fc-day',true);
11384 //Roo.log(this.cells);
11385 this.textNodes = this.el.query('.fc-day-number');
11386 this.cells.addClassOnOver('fc-state-hover');
11388 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
11389 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
11390 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
11391 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
11393 this.on('monthchange', this.onMonthChange, this);
11395 this.update(new Date().clearTime());
11398 resize : function() {
11399 var sz = this.el.getSize();
11401 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
11402 this.el.select('.fc-day-content div',true).setHeight(34);
11407 showPrevMonth : function(e){
11408 this.update(this.activeDate.add("mo", -1));
11410 showToday : function(e){
11411 this.update(new Date().clearTime());
11414 showNextMonth : function(e){
11415 this.update(this.activeDate.add("mo", 1));
11419 showPrevYear : function(){
11420 this.update(this.activeDate.add("y", -1));
11424 showNextYear : function(){
11425 this.update(this.activeDate.add("y", 1));
11430 update : function(date)
11432 var vd = this.activeDate;
11433 this.activeDate = date;
11434 // if(vd && this.el){
11435 // var t = date.getTime();
11436 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
11437 // Roo.log('using add remove');
11439 // this.fireEvent('monthchange', this, date);
11441 // this.cells.removeClass("fc-state-highlight");
11442 // this.cells.each(function(c){
11443 // if(c.dateValue == t){
11444 // c.addClass("fc-state-highlight");
11445 // setTimeout(function(){
11446 // try{c.dom.firstChild.focus();}catch(e){}
11456 var days = date.getDaysInMonth();
11458 var firstOfMonth = date.getFirstDateOfMonth();
11459 var startingPos = firstOfMonth.getDay()-this.startDay;
11461 if(startingPos < this.startDay){
11465 var pm = date.add(Date.MONTH, -1);
11466 var prevStart = pm.getDaysInMonth()-startingPos;
11468 this.cells = this.el.select('.fc-day',true);
11469 this.textNodes = this.el.query('.fc-day-number');
11470 this.cells.addClassOnOver('fc-state-hover');
11472 var cells = this.cells.elements;
11473 var textEls = this.textNodes;
11475 Roo.each(cells, function(cell){
11476 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
11479 days += startingPos;
11481 // convert everything to numbers so it's fast
11482 var day = 86400000;
11483 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
11486 //Roo.log(prevStart);
11488 var today = new Date().clearTime().getTime();
11489 var sel = date.clearTime().getTime();
11490 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
11491 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
11492 var ddMatch = this.disabledDatesRE;
11493 var ddText = this.disabledDatesText;
11494 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
11495 var ddaysText = this.disabledDaysText;
11496 var format = this.format;
11498 var setCellClass = function(cal, cell){
11500 //Roo.log('set Cell Class');
11502 var t = d.getTime();
11506 cell.dateValue = t;
11508 cell.className += " fc-today";
11509 cell.className += " fc-state-highlight";
11510 cell.title = cal.todayText;
11513 // disable highlight in other month..
11514 //cell.className += " fc-state-highlight";
11519 cell.className = " fc-state-disabled";
11520 cell.title = cal.minText;
11524 cell.className = " fc-state-disabled";
11525 cell.title = cal.maxText;
11529 if(ddays.indexOf(d.getDay()) != -1){
11530 cell.title = ddaysText;
11531 cell.className = " fc-state-disabled";
11534 if(ddMatch && format){
11535 var fvalue = d.dateFormat(format);
11536 if(ddMatch.test(fvalue)){
11537 cell.title = ddText.replace("%0", fvalue);
11538 cell.className = " fc-state-disabled";
11542 if (!cell.initialClassName) {
11543 cell.initialClassName = cell.dom.className;
11546 cell.dom.className = cell.initialClassName + ' ' + cell.className;
11551 for(; i < startingPos; i++) {
11552 textEls[i].innerHTML = (++prevStart);
11553 d.setDate(d.getDate()+1);
11555 cells[i].className = "fc-past fc-other-month";
11556 setCellClass(this, cells[i]);
11561 for(; i < days; i++){
11562 intDay = i - startingPos + 1;
11563 textEls[i].innerHTML = (intDay);
11564 d.setDate(d.getDate()+1);
11566 cells[i].className = ''; // "x-date-active";
11567 setCellClass(this, cells[i]);
11571 for(; i < 42; i++) {
11572 textEls[i].innerHTML = (++extraDays);
11573 d.setDate(d.getDate()+1);
11575 cells[i].className = "fc-future fc-other-month";
11576 setCellClass(this, cells[i]);
11579 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
11581 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
11583 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
11584 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
11586 if(totalRows != 6){
11587 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
11588 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
11591 this.fireEvent('monthchange', this, date);
11595 if(!this.internalRender){
11596 var main = this.el.dom.firstChild;
11597 var w = main.offsetWidth;
11598 this.el.setWidth(w + this.el.getBorderWidth("lr"));
11599 Roo.fly(main).setWidth(w);
11600 this.internalRender = true;
11601 // opera does not respect the auto grow header center column
11602 // then, after it gets a width opera refuses to recalculate
11603 // without a second pass
11604 if(Roo.isOpera && !this.secondPass){
11605 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
11606 this.secondPass = true;
11607 this.update.defer(10, this, [date]);
11614 findCell : function(dt) {
11615 dt = dt.clearTime().getTime();
11617 this.cells.each(function(c){
11618 //Roo.log("check " +c.dateValue + '?=' + dt);
11619 if(c.dateValue == dt){
11629 findCells : function(ev) {
11630 var s = ev.start.clone().clearTime().getTime();
11632 var e= ev.end.clone().clearTime().getTime();
11635 this.cells.each(function(c){
11636 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
11638 if(c.dateValue > e){
11641 if(c.dateValue < s){
11650 // findBestRow: function(cells)
11654 // for (var i =0 ; i < cells.length;i++) {
11655 // ret = Math.max(cells[i].rows || 0,ret);
11662 addItem : function(ev)
11664 // look for vertical location slot in
11665 var cells = this.findCells(ev);
11667 // ev.row = this.findBestRow(cells);
11669 // work out the location.
11673 for(var i =0; i < cells.length; i++) {
11681 if (crow.start.getY() == cells[i].getY()) {
11683 crow.end = cells[i];
11699 ev.rendered = false;
11700 // for (var i = 0; i < cells.length;i++) {
11701 // cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
11705 this.calevents.push(ev);
11708 clearEvents: function() {
11710 if(!this.calevents){
11714 Roo.each(this.cells.elements, function(c){
11719 Roo.each(this.calevents, function(e) {
11720 Roo.each(e.els, function(el) {
11721 el.un('mouseenter' ,this.onEventEnter, this);
11722 el.un('mouseleave' ,this.onEventLeave, this);
11727 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
11733 renderEvents: function()
11735 // first make sure there is enough space..
11736 this.cells.each(function(c) {
11741 for (var e = 0; e < this.calevents.length; e++) {
11743 var ev = this.calevents[e];
11744 var cells = ev.cells;
11745 var rows = ev.rows;
11747 for(var i = 0; i < cells.length; i++){
11749 var cbox = this.cells.item(this.cells.indexOf(cells[i]));
11751 if(cells.length < 2 && cbox.rows.length > 3){
11752 cbox.more.push(ev);
11756 cbox.rows.push(ev);
11762 this.cells.each(function(c) {
11763 if(c.more.length && c.more.length == 1){
11764 c.rows.push(c.more.pop());
11767 var r = (c.more.length) ? c.rows.length + 1 : c.rows.length;
11768 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, r * 20));
11771 for (var e = 0; e < c.rows.length; e++){
11772 var ev = c.rows[e];
11778 var cells = ev.cells;
11779 var rows = ev.rows;
11781 for(var i = 0; i < rows.length; i++) {
11783 // how many rows should it span..
11786 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
11787 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
11789 unselectable : "on",
11792 cls: 'fc-event-inner',
11796 // cls: 'fc-event-time',
11797 // html : cells.length > 1 ? '' : ev.time
11801 cls: 'fc-event-title',
11802 html : String.format('{0}', ev.title)
11809 cls: 'ui-resizable-handle ui-resizable-e',
11810 html : '  '
11817 cfg.cls += ' fc-event-start';
11819 if ((i+1) == rows.length) {
11820 cfg.cls += ' fc-event-end';
11823 var ctr = _this.el.select('.fc-event-container',true).first();
11824 var cg = ctr.createChild(cfg);
11826 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
11827 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
11829 cg.setXY([sbox.x +2, sbox.y +(e * 20)]);
11830 cg.setWidth(ebox.right - sbox.x -2);
11832 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
11833 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
11834 cg.on('click', _this.onEventClick, _this, ev);
11838 ev.rendered = true;
11846 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
11847 style : 'position: absolute',
11848 unselectable : "on",
11851 cls: 'fc-event-inner',
11855 cls: 'fc-event-title',
11863 cls: 'ui-resizable-handle ui-resizable-e',
11864 html : '  '
11870 var ctr = _this.el.select('.fc-event-container',true).first();
11871 var cg = ctr.createChild(cfg);
11873 var sbox = c.select('.fc-day-content',true).first().getBox();
11874 var ebox = c.select('.fc-day-content',true).first().getBox();
11876 cg.setXY([sbox.x +2, sbox.y +(c.rows.length * 20)]);
11877 cg.setWidth(ebox.right - sbox.x -2);
11879 cg.on('click', _this.onMoreEventClick, _this, c.more);
11889 onEventEnter: function (e, el,event,d) {
11890 this.fireEvent('evententer', this, el, event);
11893 onEventLeave: function (e, el,event,d) {
11894 this.fireEvent('eventleave', this, el, event);
11897 onEventClick: function (e, el,event,d) {
11898 this.fireEvent('eventclick', this, el, event);
11901 onMonthChange: function () {
11905 onMoreEventClick: function(e, el, more)
11909 this.calpopover.placement = 'right';
11910 this.calpopover.setTitle('More');
11912 this.calpopover.setContent('');
11914 var ctr = this.calpopover.el.select('.popover-content', true).first();
11916 Roo.each(more, function(m){
11918 cls : 'fc-event-hori fc-event-draggable',
11921 var cg = ctr.createChild(cfg);
11923 cg.on('click', _this.onEventClick, _this, m);
11926 this.calpopover.show(el);
11931 onLoad: function ()
11933 this.calevents = [];
11936 if(this.store.getCount() > 0){
11937 this.store.data.each(function(d){
11940 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
11941 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
11942 time : d.data.start_time,
11943 title : d.data.title,
11944 description : d.data.description,
11945 venue : d.data.venue
11950 this.renderEvents();
11952 if(this.calevents.length && this.loadMask){
11953 this.maskEl.hide();
11957 onBeforeLoad: function()
11959 this.clearEvents();
11961 this.maskEl.show();
11975 * @class Roo.bootstrap.Popover
11976 * @extends Roo.bootstrap.Component
11977 * Bootstrap Popover class
11978 * @cfg {String} html contents of the popover (or false to use children..)
11979 * @cfg {String} title of popover (or false to hide)
11980 * @cfg {String} placement how it is placed
11981 * @cfg {String} trigger click || hover (or false to trigger manually)
11982 * @cfg {String} over what (parent or false to trigger manually.)
11985 * Create a new Popover
11986 * @param {Object} config The config object
11989 Roo.bootstrap.Popover = function(config){
11990 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
11993 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
11995 title: 'Fill in a title',
11998 placement : 'right',
11999 trigger : 'hover', // hover
12003 can_build_overlaid : false,
12005 getChildContainer : function()
12007 return this.el.select('.popover-content',true).first();
12010 getAutoCreate : function(){
12011 Roo.log('make popover?');
12013 cls : 'popover roo-dynamic',
12014 style: 'display:block',
12020 cls : 'popover-inner',
12024 cls: 'popover-title',
12028 cls : 'popover-content',
12039 setTitle: function(str)
12041 this.el.select('.popover-title',true).first().dom.innerHTML = str;
12043 setContent: function(str)
12045 this.el.select('.popover-content',true).first().dom.innerHTML = str;
12047 // as it get's added to the bottom of the page.
12048 onRender : function(ct, position)
12050 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
12052 var cfg = Roo.apply({}, this.getAutoCreate());
12056 cfg.cls += ' ' + this.cls;
12059 cfg.style = this.style;
12061 Roo.log("adding to ")
12062 this.el = Roo.get(document.body).createChild(cfg, position);
12068 initEvents : function()
12070 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
12071 this.el.enableDisplayMode('block');
12073 if (this.over === false) {
12076 if (this.triggers === false) {
12079 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
12080 var triggers = this.trigger ? this.trigger.split(' ') : [];
12081 Roo.each(triggers, function(trigger) {
12083 if (trigger == 'click') {
12084 on_el.on('click', this.toggle, this);
12085 } else if (trigger != 'manual') {
12086 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
12087 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
12089 on_el.on(eventIn ,this.enter, this);
12090 on_el.on(eventOut, this.leave, this);
12101 toggle : function () {
12102 this.hoverState == 'in' ? this.leave() : this.enter();
12105 enter : function () {
12108 clearTimeout(this.timeout);
12110 this.hoverState = 'in'
12112 if (!this.delay || !this.delay.show) {
12117 this.timeout = setTimeout(function () {
12118 if (_t.hoverState == 'in') {
12121 }, this.delay.show)
12123 leave : function() {
12124 clearTimeout(this.timeout);
12126 this.hoverState = 'out'
12128 if (!this.delay || !this.delay.hide) {
12133 this.timeout = setTimeout(function () {
12134 if (_t.hoverState == 'out') {
12137 }, this.delay.hide)
12140 show : function (on_el)
12143 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
12146 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
12147 if (this.html !== false) {
12148 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
12150 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
12151 if (!this.title.length) {
12152 this.el.select('.popover-title',true).hide();
12155 var placement = typeof this.placement == 'function' ?
12156 this.placement.call(this, this.el, on_el) :
12159 var autoToken = /\s?auto?\s?/i;
12160 var autoPlace = autoToken.test(placement);
12162 placement = placement.replace(autoToken, '') || 'top';
12166 //this.el.setXY([0,0]);
12168 this.el.dom.style.display='block';
12169 this.el.addClass(placement);
12171 //this.el.appendTo(on_el);
12173 var p = this.getPosition();
12174 var box = this.el.getBox();
12179 var align = Roo.bootstrap.Popover.alignment[placement]
12180 this.el.alignTo(on_el, align[0],align[1]);
12181 //var arrow = this.el.select('.arrow',true).first();
12182 //arrow.set(align[2],
12184 this.el.addClass('in');
12185 this.hoverState = null;
12187 if (this.el.hasClass('fade')) {
12194 this.el.setXY([0,0]);
12195 this.el.removeClass('in');
12202 Roo.bootstrap.Popover.alignment = {
12203 'left' : ['r-l', [-10,0], 'right'],
12204 'right' : ['l-r', [10,0], 'left'],
12205 'bottom' : ['t-b', [0,10], 'top'],
12206 'top' : [ 'b-t', [0,-10], 'bottom']
12217 * @class Roo.bootstrap.Progress
12218 * @extends Roo.bootstrap.Component
12219 * Bootstrap Progress class
12220 * @cfg {Boolean} striped striped of the progress bar
12221 * @cfg {Boolean} active animated of the progress bar
12225 * Create a new Progress
12226 * @param {Object} config The config object
12229 Roo.bootstrap.Progress = function(config){
12230 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
12233 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
12238 getAutoCreate : function(){
12246 cfg.cls += ' progress-striped';
12250 cfg.cls += ' active';
12269 * @class Roo.bootstrap.ProgressBar
12270 * @extends Roo.bootstrap.Component
12271 * Bootstrap ProgressBar class
12272 * @cfg {Number} aria_valuenow aria-value now
12273 * @cfg {Number} aria_valuemin aria-value min
12274 * @cfg {Number} aria_valuemax aria-value max
12275 * @cfg {String} label label for the progress bar
12276 * @cfg {String} panel (success | info | warning | danger )
12277 * @cfg {String} role role of the progress bar
12278 * @cfg {String} sr_only text
12282 * Create a new ProgressBar
12283 * @param {Object} config The config object
12286 Roo.bootstrap.ProgressBar = function(config){
12287 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
12290 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
12294 aria_valuemax : 100,
12300 getAutoCreate : function()
12305 cls: 'progress-bar',
12306 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
12318 cfg.role = this.role;
12321 if(this.aria_valuenow){
12322 cfg['aria-valuenow'] = this.aria_valuenow;
12325 if(this.aria_valuemin){
12326 cfg['aria-valuemin'] = this.aria_valuemin;
12329 if(this.aria_valuemax){
12330 cfg['aria-valuemax'] = this.aria_valuemax;
12333 if(this.label && !this.sr_only){
12334 cfg.html = this.label;
12338 cfg.cls += ' progress-bar-' + this.panel;
12344 update : function(aria_valuenow)
12346 this.aria_valuenow = aria_valuenow;
12348 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
12363 * @class Roo.bootstrap.TabPanel
12364 * @extends Roo.bootstrap.Component
12365 * Bootstrap TabPanel class
12366 * @cfg {Boolean} active panel active
12367 * @cfg {String} html panel content
12368 * @cfg {String} tabId tab relate id
12369 * @cfg {String} navId The navbar which triggers show hide
12373 * Create a new TabPanel
12374 * @param {Object} config The config object
12377 Roo.bootstrap.TabPanel = function(config){
12378 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
12382 * Fires when the active status changes
12383 * @param {Roo.bootstrap.TabPanel} this
12384 * @param {Boolean} state the new state
12391 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
12398 getAutoCreate : function(){
12402 html: this.html || ''
12406 cfg.cls += ' active';
12410 cfg.tabId = this.tabId;
12415 onRender : function(ct, position)
12417 // Roo.log("Call onRender: " + this.xtype);
12419 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
12421 if (this.navId && this.tabId) {
12422 var item = Roo.bootstrap.NavGroup.get(this.navId).getNavItem(this.tabId);
12424 Roo.log("could not find navID:" + this.navId + ", tabId: " + this.tabId);
12426 item.on('changed', function(item, state) {
12427 this.setActive(state);
12433 setActive: function(state)
12435 Roo.log("panel - set active " + this.tabId + "=" + state);
12437 this.active = state;
12439 this.el.removeClass('active');
12441 } else if (!this.el.hasClass('active')) {
12442 this.el.addClass('active');
12444 this.fireEvent('changed', this, state);
12461 * @class Roo.bootstrap.DateField
12462 * @extends Roo.bootstrap.Input
12463 * Bootstrap DateField class
12464 * @cfg {Number} weekStart default 0
12465 * @cfg {Number} weekStart default 0
12466 * @cfg {Number} viewMode default empty, (months|years)
12467 * @cfg {Number} minViewMode default empty, (months|years)
12468 * @cfg {Number} startDate default -Infinity
12469 * @cfg {Number} endDate default Infinity
12470 * @cfg {Boolean} todayHighlight default false
12471 * @cfg {Boolean} todayBtn default false
12472 * @cfg {Boolean} calendarWeeks default false
12473 * @cfg {Object} daysOfWeekDisabled default empty
12475 * @cfg {Boolean} keyboardNavigation default true
12476 * @cfg {String} language default en
12479 * Create a new DateField
12480 * @param {Object} config The config object
12483 Roo.bootstrap.DateField = function(config){
12484 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
12488 * Fires when this field show.
12489 * @param {Roo.bootstrap.DateField} this
12490 * @param {Mixed} date The date value
12495 * Fires when this field hide.
12496 * @param {Roo.bootstrap.DateField} this
12497 * @param {Mixed} date The date value
12502 * Fires when select a date.
12503 * @param {Roo.bootstrap.DateField} this
12504 * @param {Mixed} date The date value
12510 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
12513 * @cfg {String} format
12514 * The default date format string which can be overriden for localization support. The format must be
12515 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
12519 * @cfg {String} altFormats
12520 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
12521 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
12523 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
12531 todayHighlight : false,
12537 keyboardNavigation: true,
12539 calendarWeeks: false,
12541 startDate: -Infinity,
12545 daysOfWeekDisabled: [],
12549 UTCDate: function()
12551 return new Date(Date.UTC.apply(Date, arguments));
12554 UTCToday: function()
12556 var today = new Date();
12557 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
12560 getDate: function() {
12561 var d = this.getUTCDate();
12562 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
12565 getUTCDate: function() {
12569 setDate: function(d) {
12570 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
12573 setUTCDate: function(d) {
12575 this.setValue(this.formatDate(this.date));
12578 onRender: function(ct, position)
12581 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
12583 this.language = this.language || 'en';
12584 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
12585 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
12587 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
12588 this.format = this.format || 'm/d/y';
12589 this.isInline = false;
12590 this.isInput = true;
12591 this.component = this.el.select('.add-on', true).first() || false;
12592 this.component = (this.component && this.component.length === 0) ? false : this.component;
12593 this.hasInput = this.component && this.inputEL().length;
12595 if (typeof(this.minViewMode === 'string')) {
12596 switch (this.minViewMode) {
12598 this.minViewMode = 1;
12601 this.minViewMode = 2;
12604 this.minViewMode = 0;
12609 if (typeof(this.viewMode === 'string')) {
12610 switch (this.viewMode) {
12623 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
12625 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12627 this.picker().on('mousedown', this.onMousedown, this);
12628 this.picker().on('click', this.onClick, this);
12630 this.picker().addClass('datepicker-dropdown');
12632 this.startViewMode = this.viewMode;
12635 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
12636 if(!this.calendarWeeks){
12641 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
12642 v.attr('colspan', function(i, val){
12643 return parseInt(val) + 1;
12648 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
12650 this.setStartDate(this.startDate);
12651 this.setEndDate(this.endDate);
12653 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
12660 if(this.isInline) {
12665 picker : function()
12667 return this.el.select('.datepicker', true).first();
12670 fillDow: function()
12672 var dowCnt = this.weekStart;
12681 if(this.calendarWeeks){
12689 while (dowCnt < this.weekStart + 7) {
12693 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
12697 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
12700 fillMonths: function()
12703 var months = this.picker().select('>.datepicker-months td', true).first();
12705 months.dom.innerHTML = '';
12711 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
12714 months.createChild(month);
12719 update: function(){
12721 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
12723 if (this.date < this.startDate) {
12724 this.viewDate = new Date(this.startDate);
12725 } else if (this.date > this.endDate) {
12726 this.viewDate = new Date(this.endDate);
12728 this.viewDate = new Date(this.date);
12735 var d = new Date(this.viewDate),
12736 year = d.getUTCFullYear(),
12737 month = d.getUTCMonth(),
12738 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
12739 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
12740 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
12741 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
12742 currentDate = this.date && this.date.valueOf(),
12743 today = this.UTCToday();
12745 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
12747 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
12749 // this.picker.select('>tfoot th.today').
12750 // .text(dates[this.language].today)
12751 // .toggle(this.todayBtn !== false);
12753 this.updateNavArrows();
12756 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
12758 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
12760 prevMonth.setUTCDate(day);
12762 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
12764 var nextMonth = new Date(prevMonth);
12766 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
12768 nextMonth = nextMonth.valueOf();
12770 var fillMonths = false;
12772 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
12774 while(prevMonth.valueOf() < nextMonth) {
12777 if (prevMonth.getUTCDay() === this.weekStart) {
12779 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
12787 if(this.calendarWeeks){
12788 // ISO 8601: First week contains first thursday.
12789 // ISO also states week starts on Monday, but we can be more abstract here.
12791 // Start of current week: based on weekstart/current date
12792 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
12793 // Thursday of this week
12794 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
12795 // First Thursday of year, year from thursday
12796 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
12797 // Calendar week: ms between thursdays, div ms per day, div 7 days
12798 calWeek = (th - yth) / 864e5 / 7 + 1;
12800 fillMonths.cn.push({
12808 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
12810 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
12813 if (this.todayHighlight &&
12814 prevMonth.getUTCFullYear() == today.getFullYear() &&
12815 prevMonth.getUTCMonth() == today.getMonth() &&
12816 prevMonth.getUTCDate() == today.getDate()) {
12817 clsName += ' today';
12820 if (currentDate && prevMonth.valueOf() === currentDate) {
12821 clsName += ' active';
12824 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
12825 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
12826 clsName += ' disabled';
12829 fillMonths.cn.push({
12831 cls: 'day ' + clsName,
12832 html: prevMonth.getDate()
12835 prevMonth.setDate(prevMonth.getDate()+1);
12838 var currentYear = this.date && this.date.getUTCFullYear();
12839 var currentMonth = this.date && this.date.getUTCMonth();
12841 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
12843 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
12844 v.removeClass('active');
12846 if(currentYear === year && k === currentMonth){
12847 v.addClass('active');
12850 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
12851 v.addClass('disabled');
12857 year = parseInt(year/10, 10) * 10;
12859 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
12861 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
12864 for (var i = -1; i < 11; i++) {
12865 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
12867 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
12875 showMode: function(dir) {
12877 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
12879 Roo.each(this.picker().select('>div',true).elements, function(v){
12880 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12883 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
12888 if(this.isInline) return;
12890 this.picker().removeClass(['bottom', 'top']);
12892 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
12894 * place to the top of element!
12898 this.picker().addClass('top');
12899 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12904 this.picker().addClass('bottom');
12906 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12909 parseDate : function(value){
12910 if(!value || value instanceof Date){
12913 var v = Date.parseDate(value, this.format);
12914 if (!v && this.useIso) {
12915 v = Date.parseDate(value, 'Y-m-d');
12917 if(!v && this.altFormats){
12918 if(!this.altFormatsArray){
12919 this.altFormatsArray = this.altFormats.split("|");
12921 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
12922 v = Date.parseDate(value, this.altFormatsArray[i]);
12928 formatDate : function(date, fmt){
12929 return (!date || !(date instanceof Date)) ?
12930 date : date.dateFormat(fmt || this.format);
12933 onFocus : function()
12935 Roo.bootstrap.DateField.superclass.onFocus.call(this);
12939 onBlur : function()
12941 Roo.bootstrap.DateField.superclass.onBlur.call(this);
12947 this.picker().show();
12951 this.fireEvent('show', this, this.date);
12956 if(this.isInline) return;
12957 this.picker().hide();
12958 this.viewMode = this.startViewMode;
12961 this.fireEvent('hide', this, this.date);
12965 onMousedown: function(e){
12966 e.stopPropagation();
12967 e.preventDefault();
12970 keyup: function(e){
12971 Roo.bootstrap.DateField.superclass.keyup.call(this);
12976 setValue: function(v){
12977 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
12979 this.fireEvent('select', this, this.date);
12983 fireKey: function(e){
12984 if (!this.picker().isVisible()){
12985 if (e.keyCode == 27) // allow escape to hide and re-show picker
12989 var dateChanged = false,
12991 newDate, newViewDate;
12995 e.preventDefault();
12999 if (!this.keyboardNavigation) break;
13000 dir = e.keyCode == 37 ? -1 : 1;
13003 newDate = this.moveYear(this.date, dir);
13004 newViewDate = this.moveYear(this.viewDate, dir);
13005 } else if (e.shiftKey){
13006 newDate = this.moveMonth(this.date, dir);
13007 newViewDate = this.moveMonth(this.viewDate, dir);
13009 newDate = new Date(this.date);
13010 newDate.setUTCDate(this.date.getUTCDate() + dir);
13011 newViewDate = new Date(this.viewDate);
13012 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
13014 if (this.dateWithinRange(newDate)){
13015 this.date = newDate;
13016 this.viewDate = newViewDate;
13017 this.setValue(this.formatDate(this.date));
13019 e.preventDefault();
13020 dateChanged = true;
13025 if (!this.keyboardNavigation) break;
13026 dir = e.keyCode == 38 ? -1 : 1;
13028 newDate = this.moveYear(this.date, dir);
13029 newViewDate = this.moveYear(this.viewDate, dir);
13030 } else if (e.shiftKey){
13031 newDate = this.moveMonth(this.date, dir);
13032 newViewDate = this.moveMonth(this.viewDate, dir);
13034 newDate = new Date(this.date);
13035 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
13036 newViewDate = new Date(this.viewDate);
13037 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
13039 if (this.dateWithinRange(newDate)){
13040 this.date = newDate;
13041 this.viewDate = newViewDate;
13042 this.setValue(this.formatDate(this.date));
13044 e.preventDefault();
13045 dateChanged = true;
13049 this.setValue(this.formatDate(this.date));
13051 e.preventDefault();
13054 this.setValue(this.formatDate(this.date));
13061 onClick: function(e) {
13062 e.stopPropagation();
13063 e.preventDefault();
13065 var target = e.getTarget();
13067 if(target.nodeName.toLowerCase() === 'i'){
13068 target = Roo.get(target).dom.parentNode;
13071 var nodeName = target.nodeName;
13072 var className = target.className;
13073 var html = target.innerHTML;
13075 switch(nodeName.toLowerCase()) {
13077 switch(className) {
13083 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
13084 switch(this.viewMode){
13086 this.viewDate = this.moveMonth(this.viewDate, dir);
13090 this.viewDate = this.moveYear(this.viewDate, dir);
13096 var date = new Date();
13097 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
13099 this.setValue(this.formatDate(this.date));
13105 if (className.indexOf('disabled') === -1) {
13106 this.viewDate.setUTCDate(1);
13107 if (className.indexOf('month') !== -1) {
13108 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
13110 var year = parseInt(html, 10) || 0;
13111 this.viewDate.setUTCFullYear(year);
13120 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
13121 var day = parseInt(html, 10) || 1;
13122 var year = this.viewDate.getUTCFullYear(),
13123 month = this.viewDate.getUTCMonth();
13125 if (className.indexOf('old') !== -1) {
13132 } else if (className.indexOf('new') !== -1) {
13140 this.date = this.UTCDate(year, month, day,0,0,0,0);
13141 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
13143 this.setValue(this.formatDate(this.date));
13150 setStartDate: function(startDate){
13151 this.startDate = startDate || -Infinity;
13152 if (this.startDate !== -Infinity) {
13153 this.startDate = this.parseDate(this.startDate);
13156 this.updateNavArrows();
13159 setEndDate: function(endDate){
13160 this.endDate = endDate || Infinity;
13161 if (this.endDate !== Infinity) {
13162 this.endDate = this.parseDate(this.endDate);
13165 this.updateNavArrows();
13168 setDaysOfWeekDisabled: function(daysOfWeekDisabled){
13169 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
13170 if (typeof(this.daysOfWeekDisabled) !== 'object') {
13171 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
13173 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
13174 return parseInt(d, 10);
13177 this.updateNavArrows();
13180 updateNavArrows: function() {
13181 var d = new Date(this.viewDate),
13182 year = d.getUTCFullYear(),
13183 month = d.getUTCMonth();
13185 Roo.each(this.picker().select('.prev', true).elements, function(v){
13187 switch (this.viewMode) {
13190 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
13196 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
13203 Roo.each(this.picker().select('.next', true).elements, function(v){
13205 switch (this.viewMode) {
13208 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
13214 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
13222 moveMonth: function(date, dir){
13223 if (!dir) return date;
13224 var new_date = new Date(date.valueOf()),
13225 day = new_date.getUTCDate(),
13226 month = new_date.getUTCMonth(),
13227 mag = Math.abs(dir),
13229 dir = dir > 0 ? 1 : -1;
13232 // If going back one month, make sure month is not current month
13233 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
13235 return new_date.getUTCMonth() == month;
13237 // If going forward one month, make sure month is as expected
13238 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
13240 return new_date.getUTCMonth() != new_month;
13242 new_month = month + dir;
13243 new_date.setUTCMonth(new_month);
13244 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
13245 if (new_month < 0 || new_month > 11)
13246 new_month = (new_month + 12) % 12;
13248 // For magnitudes >1, move one month at a time...
13249 for (var i=0; i<mag; i++)
13250 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
13251 new_date = this.moveMonth(new_date, dir);
13252 // ...then reset the day, keeping it in the new month
13253 new_month = new_date.getUTCMonth();
13254 new_date.setUTCDate(day);
13256 return new_month != new_date.getUTCMonth();
13259 // Common date-resetting loop -- if date is beyond end of month, make it
13262 new_date.setUTCDate(--day);
13263 new_date.setUTCMonth(new_month);
13268 moveYear: function(date, dir){
13269 return this.moveMonth(date, dir*12);
13272 dateWithinRange: function(date){
13273 return date >= this.startDate && date <= this.endDate;
13277 remove: function() {
13278 this.picker().remove();
13283 Roo.apply(Roo.bootstrap.DateField, {
13294 html: '<i class="icon-arrow-left"/>'
13304 html: '<i class="icon-arrow-right"/>'
13346 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
13347 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
13348 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
13349 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
13350 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
13363 navFnc: 'FullYear',
13368 navFnc: 'FullYear',
13373 Roo.apply(Roo.bootstrap.DateField, {
13377 cls: 'datepicker dropdown-menu',
13381 cls: 'datepicker-days',
13385 cls: 'table-condensed',
13387 Roo.bootstrap.DateField.head,
13391 Roo.bootstrap.DateField.footer
13398 cls: 'datepicker-months',
13402 cls: 'table-condensed',
13404 Roo.bootstrap.DateField.head,
13405 Roo.bootstrap.DateField.content,
13406 Roo.bootstrap.DateField.footer
13413 cls: 'datepicker-years',
13417 cls: 'table-condensed',
13419 Roo.bootstrap.DateField.head,
13420 Roo.bootstrap.DateField.content,
13421 Roo.bootstrap.DateField.footer
13440 * @class Roo.bootstrap.TimeField
13441 * @extends Roo.bootstrap.Input
13442 * Bootstrap DateField class
13446 * Create a new TimeField
13447 * @param {Object} config The config object
13450 Roo.bootstrap.TimeField = function(config){
13451 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
13455 * Fires when this field show.
13456 * @param {Roo.bootstrap.DateField} this
13457 * @param {Mixed} date The date value
13462 * Fires when this field hide.
13463 * @param {Roo.bootstrap.DateField} this
13464 * @param {Mixed} date The date value
13469 * Fires when select a date.
13470 * @param {Roo.bootstrap.DateField} this
13471 * @param {Mixed} date The date value
13477 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
13480 * @cfg {String} format
13481 * The default time format string which can be overriden for localization support. The format must be
13482 * valid according to {@link Date#parseDate} (defaults to 'H:i').
13486 onRender: function(ct, position)
13489 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
13491 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
13493 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13495 this.pop = this.picker().select('>.datepicker-time',true).first();
13496 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
13498 this.picker().on('mousedown', this.onMousedown, this);
13499 this.picker().on('click', this.onClick, this);
13501 this.picker().addClass('datepicker-dropdown');
13506 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
13507 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
13508 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
13509 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
13510 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
13511 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
13515 fireKey: function(e){
13516 if (!this.picker().isVisible()){
13517 if (e.keyCode == 27) // allow escape to hide and re-show picker
13522 e.preventDefault();
13530 this.onTogglePeriod();
13533 this.onIncrementMinutes();
13536 this.onDecrementMinutes();
13545 onClick: function(e) {
13546 e.stopPropagation();
13547 e.preventDefault();
13550 picker : function()
13552 return this.el.select('.datepicker', true).first();
13555 fillTime: function()
13557 var time = this.pop.select('tbody', true).first();
13559 time.dom.innerHTML = '';
13574 cls: 'hours-up glyphicon glyphicon-chevron-up'
13594 cls: 'minutes-up glyphicon glyphicon-chevron-up'
13615 cls: 'timepicker-hour',
13630 cls: 'timepicker-minute',
13645 cls: 'btn btn-primary period',
13667 cls: 'hours-down glyphicon glyphicon-chevron-down'
13687 cls: 'minutes-down glyphicon glyphicon-chevron-down'
13705 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
13712 var hours = this.time.getHours();
13713 var minutes = this.time.getMinutes();
13726 hours = hours - 12;
13730 hours = '0' + hours;
13734 minutes = '0' + minutes;
13737 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
13738 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
13739 this.pop.select('button', true).first().dom.innerHTML = period;
13745 this.picker().removeClass(['bottom', 'top']);
13747 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
13749 * place to the top of element!
13753 this.picker().addClass('top');
13754 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13759 this.picker().addClass('bottom');
13761 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13764 onFocus : function()
13766 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
13770 onBlur : function()
13772 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
13778 this.picker().show();
13783 this.fireEvent('show', this, this.date);
13788 this.picker().hide();
13791 this.fireEvent('hide', this, this.date);
13794 setTime : function()
13797 this.setValue(this.time.format(this.format));
13799 this.fireEvent('select', this, this.date);
13804 onMousedown: function(e){
13805 e.stopPropagation();
13806 e.preventDefault();
13809 onIncrementHours: function()
13811 Roo.log('onIncrementHours');
13812 this.time = this.time.add(Date.HOUR, 1);
13817 onDecrementHours: function()
13819 Roo.log('onDecrementHours');
13820 this.time = this.time.add(Date.HOUR, -1);
13824 onIncrementMinutes: function()
13826 Roo.log('onIncrementMinutes');
13827 this.time = this.time.add(Date.MINUTE, 1);
13831 onDecrementMinutes: function()
13833 Roo.log('onDecrementMinutes');
13834 this.time = this.time.add(Date.MINUTE, -1);
13838 onTogglePeriod: function()
13840 Roo.log('onTogglePeriod');
13841 this.time = this.time.add(Date.HOUR, 12);
13848 Roo.apply(Roo.bootstrap.TimeField, {
13878 cls: 'btn btn-info ok',
13890 Roo.apply(Roo.bootstrap.TimeField, {
13894 cls: 'datepicker dropdown-menu',
13898 cls: 'datepicker-time',
13902 cls: 'table-condensed',
13904 Roo.bootstrap.TimeField.content,
13905 Roo.bootstrap.TimeField.footer
13924 * @class Roo.bootstrap.CheckBox
13925 * @extends Roo.bootstrap.Input
13926 * Bootstrap CheckBox class
13928 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
13929 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
13930 * @cfg {String} boxLabel The text that appears beside the checkbox
13931 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
13932 * @cfg {Boolean} checked initnal the element
13936 * Create a new CheckBox
13937 * @param {Object} config The config object
13940 Roo.bootstrap.CheckBox = function(config){
13941 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
13946 * Fires when the element is checked or unchecked.
13947 * @param {Roo.bootstrap.CheckBox} this This input
13948 * @param {Boolean} checked The new checked value
13954 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
13956 inputType: 'checkbox',
13963 getAutoCreate : function()
13965 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
13971 cfg.cls = 'form-group checkbox' //input-group
13979 type : this.inputType,
13980 value : (!this.checked) ? this.valueOff : this.inputValue,
13981 cls : 'roo-checkbox', //'form-box',
13982 placeholder : this.placeholder || ''
13986 if (this.weight) { // Validity check?
13987 cfg.cls += " checkbox-" + this.weight;
13990 if (this.disabled) {
13991 input.disabled=true;
13995 input.checked = this.checked;
13999 input.name = this.name;
14003 input.cls += ' input-' + this.size;
14007 ['xs','sm','md','lg'].map(function(size){
14008 if (settings[size]) {
14009 cfg.cls += ' col-' + size + '-' + settings[size];
14015 var inputblock = input;
14020 if (this.before || this.after) {
14023 cls : 'input-group',
14027 inputblock.cn.push({
14029 cls : 'input-group-addon',
14033 inputblock.cn.push(input);
14035 inputblock.cn.push({
14037 cls : 'input-group-addon',
14044 if (align ==='left' && this.fieldLabel.length) {
14045 Roo.log("left and has label");
14051 cls : 'control-label col-md-' + this.labelWidth,
14052 html : this.fieldLabel
14056 cls : "col-md-" + (12 - this.labelWidth),
14063 } else if ( this.fieldLabel.length) {
14068 tag: this.boxLabel ? 'span' : 'label',
14070 cls: 'control-label box-input-label',
14071 //cls : 'input-group-addon',
14072 html : this.fieldLabel
14082 Roo.log(" no label && no align");
14083 cfg.cn = [ inputblock ] ;
14092 html: this.boxLabel
14104 * return the real input element.
14106 inputEl: function ()
14108 return this.el.select('input.roo-checkbox',true).first();
14113 return this.el.select('label.control-label',true).first();
14116 initEvents : function()
14118 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
14120 this.inputEl().on('click', this.onClick, this);
14124 onClick : function()
14126 this.setChecked(!this.checked);
14129 setChecked : function(state,suppressEvent)
14131 this.checked = state;
14133 this.inputEl().dom.checked = state;
14135 if(suppressEvent !== true){
14136 this.fireEvent('check', this, state);
14139 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
14143 setValue : function(v,suppressEvent)
14145 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
14159 * @class Roo.bootstrap.Radio
14160 * @extends Roo.bootstrap.CheckBox
14161 * Bootstrap Radio class
14164 * Create a new Radio
14165 * @param {Object} config The config object
14168 Roo.bootstrap.Radio = function(config){
14169 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
14173 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
14175 inputType: 'radio',
14179 getAutoCreate : function()
14181 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
14187 cfg.cls = 'form-group radio' //input-group
14192 type : this.inputType,
14193 value : (!this.checked) ? this.valueOff : this.inputValue,
14195 placeholder : this.placeholder || ''
14198 if (this.weight) { // Validity check?
14199 cfg.cls += " radio-" + this.weight;
14201 if (this.disabled) {
14202 input.disabled=true;
14206 input.checked = this.checked;
14210 input.name = this.name;
14214 input.cls += ' input-' + this.size;
14218 ['xs','sm','md','lg'].map(function(size){
14219 if (settings[size]) {
14220 cfg.cls += ' col-' + size + '-' + settings[size];
14224 var inputblock = input;
14226 if (this.before || this.after) {
14229 cls : 'input-group',
14233 inputblock.cn.push({
14235 cls : 'input-group-addon',
14239 inputblock.cn.push(input);
14241 inputblock.cn.push({
14243 cls : 'input-group-addon',
14250 if (align ==='left' && this.fieldLabel.length) {
14251 Roo.log("left and has label");
14257 cls : 'control-label col-md-' + this.labelWidth,
14258 html : this.fieldLabel
14262 cls : "col-md-" + (12 - this.labelWidth),
14269 } else if ( this.fieldLabel.length) {
14276 cls: 'control-label box-input-label',
14277 //cls : 'input-group-addon',
14278 html : this.fieldLabel
14288 Roo.log(" no label && no align");
14303 html: this.boxLabel
14310 inputEl: function ()
14312 return this.el.select('input.roo-radio',true).first();
14314 onClick : function()
14316 this.setChecked(true);
14319 setChecked : function(state,suppressEvent)
14322 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
14323 v.dom.checked = false;
14327 this.checked = state;
14328 this.inputEl().dom.checked = state;
14330 if(suppressEvent !== true){
14331 this.fireEvent('check', this, state);
14334 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
14338 getGroupValue : function()
14341 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
14342 if(v.dom.checked == true){
14343 value = v.dom.value;
14351 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
14352 * @return {Mixed} value The field value
14354 getValue : function(){
14355 return this.getGroupValue();
14361 //<script type="text/javascript">
14364 * Based Ext JS Library 1.1.1
14365 * Copyright(c) 2006-2007, Ext JS, LLC.
14371 * @class Roo.HtmlEditorCore
14372 * @extends Roo.Component
14373 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
14375 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
14378 Roo.HtmlEditorCore = function(config){
14381 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
14384 * @event initialize
14385 * Fires when the editor is fully initialized (including the iframe)
14386 * @param {Roo.HtmlEditorCore} this
14391 * Fires when the editor is first receives the focus. Any insertion must wait
14392 * until after this event.
14393 * @param {Roo.HtmlEditorCore} this
14397 * @event beforesync
14398 * Fires before the textarea is updated with content from the editor iframe. Return false
14399 * to cancel the sync.
14400 * @param {Roo.HtmlEditorCore} this
14401 * @param {String} html
14405 * @event beforepush
14406 * Fires before the iframe editor is updated with content from the textarea. Return false
14407 * to cancel the push.
14408 * @param {Roo.HtmlEditorCore} this
14409 * @param {String} html
14414 * Fires when the textarea is updated with content from the editor iframe.
14415 * @param {Roo.HtmlEditorCore} this
14416 * @param {String} html
14421 * Fires when the iframe editor is updated with content from the textarea.
14422 * @param {Roo.HtmlEditorCore} this
14423 * @param {String} html
14428 * @event editorevent
14429 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
14430 * @param {Roo.HtmlEditorCore} this
14438 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
14442 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
14448 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
14453 * @cfg {Number} height (in pixels)
14457 * @cfg {Number} width (in pixels)
14462 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
14465 stylesheets: false,
14470 // private properties
14471 validationEvent : false,
14473 initialized : false,
14475 sourceEditMode : false,
14476 onFocus : Roo.emptyFn,
14478 hideMode:'offsets',
14486 * Protected method that will not generally be called directly. It
14487 * is called when the editor initializes the iframe with HTML contents. Override this method if you
14488 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
14490 getDocMarkup : function(){
14493 Roo.log(this.stylesheets);
14495 // inherit styels from page...??
14496 if (this.stylesheets === false) {
14498 Roo.get(document.head).select('style').each(function(node) {
14499 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
14502 Roo.get(document.head).select('link').each(function(node) {
14503 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
14506 } else if (!this.stylesheets.length) {
14508 st = '<style type="text/css">' +
14509 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
14512 Roo.each(this.stylesheets, function(s) {
14513 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
14518 st += '<style type="text/css">' +
14519 'IMG { cursor: pointer } ' +
14523 return '<html><head>' + st +
14524 //<style type="text/css">' +
14525 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
14527 ' </head><body class="roo-htmleditor-body"></body></html>';
14531 onRender : function(ct, position)
14534 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
14535 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
14538 this.el.dom.style.border = '0 none';
14539 this.el.dom.setAttribute('tabIndex', -1);
14540 this.el.addClass('x-hidden hide');
14544 if(Roo.isIE){ // fix IE 1px bogus margin
14545 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
14549 this.frameId = Roo.id();
14553 var iframe = this.owner.wrap.createChild({
14555 cls: 'form-control', // bootstrap..
14557 name: this.frameId,
14558 frameBorder : 'no',
14559 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
14564 this.iframe = iframe.dom;
14566 this.assignDocWin();
14568 this.doc.designMode = 'on';
14571 this.doc.write(this.getDocMarkup());
14575 var task = { // must defer to wait for browser to be ready
14577 //console.log("run task?" + this.doc.readyState);
14578 this.assignDocWin();
14579 if(this.doc.body || this.doc.readyState == 'complete'){
14581 this.doc.designMode="on";
14585 Roo.TaskMgr.stop(task);
14586 this.initEditor.defer(10, this);
14593 Roo.TaskMgr.start(task);
14600 onResize : function(w, h)
14602 Roo.log('resize: ' +w + ',' + h );
14603 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
14607 if(typeof w == 'number'){
14609 this.iframe.style.width = w + 'px';
14611 if(typeof h == 'number'){
14613 this.iframe.style.height = h + 'px';
14615 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
14622 * Toggles the editor between standard and source edit mode.
14623 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
14625 toggleSourceEdit : function(sourceEditMode){
14627 this.sourceEditMode = sourceEditMode === true;
14629 if(this.sourceEditMode){
14631 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
14634 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
14635 //this.iframe.className = '';
14638 //this.setSize(this.owner.wrap.getSize());
14639 //this.fireEvent('editmodechange', this, this.sourceEditMode);
14646 * Protected method that will not generally be called directly. If you need/want
14647 * custom HTML cleanup, this is the method you should override.
14648 * @param {String} html The HTML to be cleaned
14649 * return {String} The cleaned HTML
14651 cleanHtml : function(html){
14652 html = String(html);
14653 if(html.length > 5){
14654 if(Roo.isSafari){ // strip safari nonsense
14655 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
14658 if(html == ' '){
14665 * HTML Editor -> Textarea
14666 * Protected method that will not generally be called directly. Syncs the contents
14667 * of the editor iframe with the textarea.
14669 syncValue : function(){
14670 if(this.initialized){
14671 var bd = (this.doc.body || this.doc.documentElement);
14672 //this.cleanUpPaste(); -- this is done else where and causes havoc..
14673 var html = bd.innerHTML;
14675 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
14676 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
14678 html = '<div style="'+m[0]+'">' + html + '</div>';
14681 html = this.cleanHtml(html);
14682 // fix up the special chars.. normaly like back quotes in word...
14683 // however we do not want to do this with chinese..
14684 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
14685 var cc = b.charCodeAt();
14687 (cc >= 0x4E00 && cc < 0xA000 ) ||
14688 (cc >= 0x3400 && cc < 0x4E00 ) ||
14689 (cc >= 0xf900 && cc < 0xfb00 )
14695 if(this.owner.fireEvent('beforesync', this, html) !== false){
14696 this.el.dom.value = html;
14697 this.owner.fireEvent('sync', this, html);
14703 * Protected method that will not generally be called directly. Pushes the value of the textarea
14704 * into the iframe editor.
14706 pushValue : function(){
14707 if(this.initialized){
14708 var v = this.el.dom.value.trim();
14710 // if(v.length < 1){
14714 if(this.owner.fireEvent('beforepush', this, v) !== false){
14715 var d = (this.doc.body || this.doc.documentElement);
14717 this.cleanUpPaste();
14718 this.el.dom.value = d.innerHTML;
14719 this.owner.fireEvent('push', this, v);
14725 deferFocus : function(){
14726 this.focus.defer(10, this);
14730 focus : function(){
14731 if(this.win && !this.sourceEditMode){
14738 assignDocWin: function()
14740 var iframe = this.iframe;
14743 this.doc = iframe.contentWindow.document;
14744 this.win = iframe.contentWindow;
14746 if (!Roo.get(this.frameId)) {
14749 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
14750 this.win = Roo.get(this.frameId).dom.contentWindow;
14755 initEditor : function(){
14756 //console.log("INIT EDITOR");
14757 this.assignDocWin();
14761 this.doc.designMode="on";
14763 this.doc.write(this.getDocMarkup());
14766 var dbody = (this.doc.body || this.doc.documentElement);
14767 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
14768 // this copies styles from the containing element into thsi one..
14769 // not sure why we need all of this..
14770 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
14771 ss['background-attachment'] = 'fixed'; // w3c
14772 dbody.bgProperties = 'fixed'; // ie
14773 Roo.DomHelper.applyStyles(dbody, ss);
14774 Roo.EventManager.on(this.doc, {
14775 //'mousedown': this.onEditorEvent,
14776 'mouseup': this.onEditorEvent,
14777 'dblclick': this.onEditorEvent,
14778 'click': this.onEditorEvent,
14779 'keyup': this.onEditorEvent,
14784 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
14786 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
14787 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
14789 this.initialized = true;
14791 this.owner.fireEvent('initialize', this);
14796 onDestroy : function(){
14802 //for (var i =0; i < this.toolbars.length;i++) {
14803 // // fixme - ask toolbars for heights?
14804 // this.toolbars[i].onDestroy();
14807 //this.wrap.dom.innerHTML = '';
14808 //this.wrap.remove();
14813 onFirstFocus : function(){
14815 this.assignDocWin();
14818 this.activated = true;
14821 if(Roo.isGecko){ // prevent silly gecko errors
14823 var s = this.win.getSelection();
14824 if(!s.focusNode || s.focusNode.nodeType != 3){
14825 var r = s.getRangeAt(0);
14826 r.selectNodeContents((this.doc.body || this.doc.documentElement));
14831 this.execCmd('useCSS', true);
14832 this.execCmd('styleWithCSS', false);
14835 this.owner.fireEvent('activate', this);
14839 adjustFont: function(btn){
14840 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
14841 //if(Roo.isSafari){ // safari
14844 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
14845 if(Roo.isSafari){ // safari
14846 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
14847 v = (v < 10) ? 10 : v;
14848 v = (v > 48) ? 48 : v;
14849 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
14854 v = Math.max(1, v+adjust);
14856 this.execCmd('FontSize', v );
14859 onEditorEvent : function(e){
14860 this.owner.fireEvent('editorevent', this, e);
14861 // this.updateToolbar();
14862 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
14865 insertTag : function(tg)
14867 // could be a bit smarter... -> wrap the current selected tRoo..
14868 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
14870 range = this.createRange(this.getSelection());
14871 var wrappingNode = this.doc.createElement(tg.toLowerCase());
14872 wrappingNode.appendChild(range.extractContents());
14873 range.insertNode(wrappingNode);
14880 this.execCmd("formatblock", tg);
14884 insertText : function(txt)
14888 var range = this.createRange();
14889 range.deleteContents();
14890 //alert(Sender.getAttribute('label'));
14892 range.insertNode(this.doc.createTextNode(txt));
14898 * Executes a Midas editor command on the editor document and performs necessary focus and
14899 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
14900 * @param {String} cmd The Midas command
14901 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
14903 relayCmd : function(cmd, value){
14905 this.execCmd(cmd, value);
14906 this.owner.fireEvent('editorevent', this);
14907 //this.updateToolbar();
14908 this.owner.deferFocus();
14912 * Executes a Midas editor command directly on the editor document.
14913 * For visual commands, you should use {@link #relayCmd} instead.
14914 * <b>This should only be called after the editor is initialized.</b>
14915 * @param {String} cmd The Midas command
14916 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
14918 execCmd : function(cmd, value){
14919 this.doc.execCommand(cmd, false, value === undefined ? null : value);
14926 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
14928 * @param {String} text | dom node..
14930 insertAtCursor : function(text)
14935 if(!this.activated){
14941 var r = this.doc.selection.createRange();
14952 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
14956 // from jquery ui (MIT licenced)
14958 var win = this.win;
14960 if (win.getSelection && win.getSelection().getRangeAt) {
14961 range = win.getSelection().getRangeAt(0);
14962 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
14963 range.insertNode(node);
14964 } else if (win.document.selection && win.document.selection.createRange) {
14965 // no firefox support
14966 var txt = typeof(text) == 'string' ? text : text.outerHTML;
14967 win.document.selection.createRange().pasteHTML(txt);
14969 // no firefox support
14970 var txt = typeof(text) == 'string' ? text : text.outerHTML;
14971 this.execCmd('InsertHTML', txt);
14980 mozKeyPress : function(e){
14982 var c = e.getCharCode(), cmd;
14985 c = String.fromCharCode(c).toLowerCase();
14999 this.cleanUpPaste.defer(100, this);
15007 e.preventDefault();
15015 fixKeys : function(){ // load time branching for fastest keydown performance
15017 return function(e){
15018 var k = e.getKey(), r;
15021 r = this.doc.selection.createRange();
15024 r.pasteHTML('    ');
15031 r = this.doc.selection.createRange();
15033 var target = r.parentElement();
15034 if(!target || target.tagName.toLowerCase() != 'li'){
15036 r.pasteHTML('<br />');
15042 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
15043 this.cleanUpPaste.defer(100, this);
15049 }else if(Roo.isOpera){
15050 return function(e){
15051 var k = e.getKey();
15055 this.execCmd('InsertHTML','    ');
15058 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
15059 this.cleanUpPaste.defer(100, this);
15064 }else if(Roo.isSafari){
15065 return function(e){
15066 var k = e.getKey();
15070 this.execCmd('InsertText','\t');
15074 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
15075 this.cleanUpPaste.defer(100, this);
15083 getAllAncestors: function()
15085 var p = this.getSelectedNode();
15088 a.push(p); // push blank onto stack..
15089 p = this.getParentElement();
15093 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
15097 a.push(this.doc.body);
15101 lastSelNode : false,
15104 getSelection : function()
15106 this.assignDocWin();
15107 return Roo.isIE ? this.doc.selection : this.win.getSelection();
15110 getSelectedNode: function()
15112 // this may only work on Gecko!!!
15114 // should we cache this!!!!
15119 var range = this.createRange(this.getSelection()).cloneRange();
15122 var parent = range.parentElement();
15124 var testRange = range.duplicate();
15125 testRange.moveToElementText(parent);
15126 if (testRange.inRange(range)) {
15129 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
15132 parent = parent.parentElement;
15137 // is ancestor a text element.
15138 var ac = range.commonAncestorContainer;
15139 if (ac.nodeType == 3) {
15140 ac = ac.parentNode;
15143 var ar = ac.childNodes;
15146 var other_nodes = [];
15147 var has_other_nodes = false;
15148 for (var i=0;i<ar.length;i++) {
15149 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
15152 // fullly contained node.
15154 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
15159 // probably selected..
15160 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
15161 other_nodes.push(ar[i]);
15165 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
15170 has_other_nodes = true;
15172 if (!nodes.length && other_nodes.length) {
15173 nodes= other_nodes;
15175 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
15181 createRange: function(sel)
15183 // this has strange effects when using with
15184 // top toolbar - not sure if it's a great idea.
15185 //this.editor.contentWindow.focus();
15186 if (typeof sel != "undefined") {
15188 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
15190 return this.doc.createRange();
15193 return this.doc.createRange();
15196 getParentElement: function()
15199 this.assignDocWin();
15200 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
15202 var range = this.createRange(sel);
15205 var p = range.commonAncestorContainer;
15206 while (p.nodeType == 3) { // text node
15217 * Range intersection.. the hard stuff...
15221 * [ -- selected range --- ]
15225 * if end is before start or hits it. fail.
15226 * if start is after end or hits it fail.
15228 * if either hits (but other is outside. - then it's not
15234 // @see http://www.thismuchiknow.co.uk/?p=64.
15235 rangeIntersectsNode : function(range, node)
15237 var nodeRange = node.ownerDocument.createRange();
15239 nodeRange.selectNode(node);
15241 nodeRange.selectNodeContents(node);
15244 var rangeStartRange = range.cloneRange();
15245 rangeStartRange.collapse(true);
15247 var rangeEndRange = range.cloneRange();
15248 rangeEndRange.collapse(false);
15250 var nodeStartRange = nodeRange.cloneRange();
15251 nodeStartRange.collapse(true);
15253 var nodeEndRange = nodeRange.cloneRange();
15254 nodeEndRange.collapse(false);
15256 return rangeStartRange.compareBoundaryPoints(
15257 Range.START_TO_START, nodeEndRange) == -1 &&
15258 rangeEndRange.compareBoundaryPoints(
15259 Range.START_TO_START, nodeStartRange) == 1;
15263 rangeCompareNode : function(range, node)
15265 var nodeRange = node.ownerDocument.createRange();
15267 nodeRange.selectNode(node);
15269 nodeRange.selectNodeContents(node);
15273 range.collapse(true);
15275 nodeRange.collapse(true);
15277 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
15278 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
15280 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
15282 var nodeIsBefore = ss == 1;
15283 var nodeIsAfter = ee == -1;
15285 if (nodeIsBefore && nodeIsAfter)
15287 if (!nodeIsBefore && nodeIsAfter)
15288 return 1; //right trailed.
15290 if (nodeIsBefore && !nodeIsAfter)
15291 return 2; // left trailed.
15296 // private? - in a new class?
15297 cleanUpPaste : function()
15299 // cleans up the whole document..
15300 Roo.log('cleanuppaste');
15302 this.cleanUpChildren(this.doc.body);
15303 var clean = this.cleanWordChars(this.doc.body.innerHTML);
15304 if (clean != this.doc.body.innerHTML) {
15305 this.doc.body.innerHTML = clean;
15310 cleanWordChars : function(input) {// change the chars to hex code
15311 var he = Roo.HtmlEditorCore;
15313 var output = input;
15314 Roo.each(he.swapCodes, function(sw) {
15315 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
15317 output = output.replace(swapper, sw[1]);
15324 cleanUpChildren : function (n)
15326 if (!n.childNodes.length) {
15329 for (var i = n.childNodes.length-1; i > -1 ; i--) {
15330 this.cleanUpChild(n.childNodes[i]);
15337 cleanUpChild : function (node)
15340 //console.log(node);
15341 if (node.nodeName == "#text") {
15342 // clean up silly Windows -- stuff?
15345 if (node.nodeName == "#comment") {
15346 node.parentNode.removeChild(node);
15347 // clean up silly Windows -- stuff?
15351 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
15353 node.parentNode.removeChild(node);
15358 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
15360 // remove <a name=....> as rendering on yahoo mailer is borked with this.
15361 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
15363 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
15364 // remove_keep_children = true;
15367 if (remove_keep_children) {
15368 this.cleanUpChildren(node);
15369 // inserts everything just before this node...
15370 while (node.childNodes.length) {
15371 var cn = node.childNodes[0];
15372 node.removeChild(cn);
15373 node.parentNode.insertBefore(cn, node);
15375 node.parentNode.removeChild(node);
15379 if (!node.attributes || !node.attributes.length) {
15380 this.cleanUpChildren(node);
15384 function cleanAttr(n,v)
15387 if (v.match(/^\./) || v.match(/^\//)) {
15390 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
15393 if (v.match(/^#/)) {
15396 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
15397 node.removeAttribute(n);
15401 function cleanStyle(n,v)
15403 if (v.match(/expression/)) { //XSS?? should we even bother..
15404 node.removeAttribute(n);
15407 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
15408 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
15411 var parts = v.split(/;/);
15414 Roo.each(parts, function(p) {
15415 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
15419 var l = p.split(':').shift().replace(/\s+/g,'');
15420 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
15422 if ( cblack.indexOf(l) > -1) {
15423 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
15424 //node.removeAttribute(n);
15428 // only allow 'c whitelisted system attributes'
15429 if ( cwhite.length && cwhite.indexOf(l) < 0) {
15430 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
15431 //node.removeAttribute(n);
15441 if (clean.length) {
15442 node.setAttribute(n, clean.join(';'));
15444 node.removeAttribute(n);
15450 for (var i = node.attributes.length-1; i > -1 ; i--) {
15451 var a = node.attributes[i];
15454 if (a.name.toLowerCase().substr(0,2)=='on') {
15455 node.removeAttribute(a.name);
15458 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
15459 node.removeAttribute(a.name);
15462 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
15463 cleanAttr(a.name,a.value); // fixme..
15466 if (a.name == 'style') {
15467 cleanStyle(a.name,a.value);
15470 /// clean up MS crap..
15471 // tecnically this should be a list of valid class'es..
15474 if (a.name == 'class') {
15475 if (a.value.match(/^Mso/)) {
15476 node.className = '';
15479 if (a.value.match(/body/)) {
15480 node.className = '';
15491 this.cleanUpChildren(node);
15496 * Clean up MS wordisms...
15498 cleanWord : function(node)
15501 var cleanWordChildren = function()
15503 if (!node.childNodes.length) {
15506 for (var i = node.childNodes.length-1; i > -1 ; i--) {
15507 _t.cleanWord(node.childNodes[i]);
15513 this.cleanWord(this.doc.body);
15516 if (node.nodeName == "#text") {
15517 // clean up silly Windows -- stuff?
15520 if (node.nodeName == "#comment") {
15521 node.parentNode.removeChild(node);
15522 // clean up silly Windows -- stuff?
15526 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
15527 node.parentNode.removeChild(node);
15531 // remove - but keep children..
15532 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
15533 while (node.childNodes.length) {
15534 var cn = node.childNodes[0];
15535 node.removeChild(cn);
15536 node.parentNode.insertBefore(cn, node);
15538 node.parentNode.removeChild(node);
15539 cleanWordChildren();
15543 if (node.className.length) {
15545 var cn = node.className.split(/\W+/);
15547 Roo.each(cn, function(cls) {
15548 if (cls.match(/Mso[a-zA-Z]+/)) {
15553 node.className = cna.length ? cna.join(' ') : '';
15555 node.removeAttribute("class");
15559 if (node.hasAttribute("lang")) {
15560 node.removeAttribute("lang");
15563 if (node.hasAttribute("style")) {
15565 var styles = node.getAttribute("style").split(";");
15567 Roo.each(styles, function(s) {
15568 if (!s.match(/:/)) {
15571 var kv = s.split(":");
15572 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
15575 // what ever is left... we allow.
15578 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
15579 if (!nstyle.length) {
15580 node.removeAttribute('style');
15584 cleanWordChildren();
15588 domToHTML : function(currentElement, depth, nopadtext) {
15590 depth = depth || 0;
15591 nopadtext = nopadtext || false;
15593 if (!currentElement) {
15594 return this.domToHTML(this.doc.body);
15597 //Roo.log(currentElement);
15599 var allText = false;
15600 var nodeName = currentElement.nodeName;
15601 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
15603 if (nodeName == '#text') {
15604 return currentElement.nodeValue;
15609 if (nodeName != 'BODY') {
15612 // Prints the node tagName, such as <A>, <IMG>, etc
15615 for(i = 0; i < currentElement.attributes.length;i++) {
15617 var aname = currentElement.attributes.item(i).name;
15618 if (!currentElement.attributes.item(i).value.length) {
15621 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
15624 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
15633 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
15636 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
15641 // Traverse the tree
15643 var currentElementChild = currentElement.childNodes.item(i);
15644 var allText = true;
15645 var innerHTML = '';
15647 while (currentElementChild) {
15648 // Formatting code (indent the tree so it looks nice on the screen)
15649 var nopad = nopadtext;
15650 if (lastnode == 'SPAN') {
15654 if (currentElementChild.nodeName == '#text') {
15655 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
15656 if (!nopad && toadd.length > 80) {
15657 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
15659 innerHTML += toadd;
15662 currentElementChild = currentElement.childNodes.item(i);
15668 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
15670 // Recursively traverse the tree structure of the child node
15671 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
15672 lastnode = currentElementChild.nodeName;
15674 currentElementChild=currentElement.childNodes.item(i);
15680 // The remaining code is mostly for formatting the tree
15681 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
15686 ret+= "</"+tagName+">";
15692 // hide stuff that is not compatible
15706 * @event specialkey
15710 * @cfg {String} fieldClass @hide
15713 * @cfg {String} focusClass @hide
15716 * @cfg {String} autoCreate @hide
15719 * @cfg {String} inputType @hide
15722 * @cfg {String} invalidClass @hide
15725 * @cfg {String} invalidText @hide
15728 * @cfg {String} msgFx @hide
15731 * @cfg {String} validateOnBlur @hide
15735 Roo.HtmlEditorCore.white = [
15736 'area', 'br', 'img', 'input', 'hr', 'wbr',
15738 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
15739 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
15740 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
15741 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
15742 'table', 'ul', 'xmp',
15744 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
15747 'dir', 'menu', 'ol', 'ul', 'dl',
15753 Roo.HtmlEditorCore.black = [
15754 // 'embed', 'object', // enable - backend responsiblity to clean thiese
15756 'base', 'basefont', 'bgsound', 'blink', 'body',
15757 'frame', 'frameset', 'head', 'html', 'ilayer',
15758 'iframe', 'layer', 'link', 'meta', 'object',
15759 'script', 'style' ,'title', 'xml' // clean later..
15761 Roo.HtmlEditorCore.clean = [
15762 'script', 'style', 'title', 'xml'
15764 Roo.HtmlEditorCore.remove = [
15769 Roo.HtmlEditorCore.ablack = [
15773 Roo.HtmlEditorCore.aclean = [
15774 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
15778 Roo.HtmlEditorCore.pwhite= [
15779 'http', 'https', 'mailto'
15782 // white listed style attributes.
15783 Roo.HtmlEditorCore.cwhite= [
15784 // 'text-align', /// default is to allow most things..
15790 // black listed style attributes.
15791 Roo.HtmlEditorCore.cblack= [
15792 // 'font-size' -- this can be set by the project
15796 Roo.HtmlEditorCore.swapCodes =[
15815 * @class Roo.bootstrap.HtmlEditor
15816 * @extends Roo.bootstrap.TextArea
15817 * Bootstrap HtmlEditor class
15820 * Create a new HtmlEditor
15821 * @param {Object} config The config object
15824 Roo.bootstrap.HtmlEditor = function(config){
15825 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
15826 if (!this.toolbars) {
15827 this.toolbars = [];
15829 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
15832 * @event initialize
15833 * Fires when the editor is fully initialized (including the iframe)
15834 * @param {HtmlEditor} this
15839 * Fires when the editor is first receives the focus. Any insertion must wait
15840 * until after this event.
15841 * @param {HtmlEditor} this
15845 * @event beforesync
15846 * Fires before the textarea is updated with content from the editor iframe. Return false
15847 * to cancel the sync.
15848 * @param {HtmlEditor} this
15849 * @param {String} html
15853 * @event beforepush
15854 * Fires before the iframe editor is updated with content from the textarea. Return false
15855 * to cancel the push.
15856 * @param {HtmlEditor} this
15857 * @param {String} html
15862 * Fires when the textarea is updated with content from the editor iframe.
15863 * @param {HtmlEditor} this
15864 * @param {String} html
15869 * Fires when the iframe editor is updated with content from the textarea.
15870 * @param {HtmlEditor} this
15871 * @param {String} html
15875 * @event editmodechange
15876 * Fires when the editor switches edit modes
15877 * @param {HtmlEditor} this
15878 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
15880 editmodechange: true,
15882 * @event editorevent
15883 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
15884 * @param {HtmlEditor} this
15888 * @event firstfocus
15889 * Fires when on first focus - needed by toolbars..
15890 * @param {HtmlEditor} this
15895 * Auto save the htmlEditor value as a file into Events
15896 * @param {HtmlEditor} this
15900 * @event savedpreview
15901 * preview the saved version of htmlEditor
15902 * @param {HtmlEditor} this
15909 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
15913 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
15918 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
15923 * @cfg {Number} height (in pixels)
15927 * @cfg {Number} width (in pixels)
15932 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
15935 stylesheets: false,
15940 // private properties
15941 validationEvent : false,
15943 initialized : false,
15946 onFocus : Roo.emptyFn,
15948 hideMode:'offsets',
15951 tbContainer : false,
15953 toolbarContainer :function() {
15954 return this.wrap.select('.x-html-editor-tb',true).first();
15958 * Protected method that will not generally be called directly. It
15959 * is called when the editor creates its toolbar. Override this method if you need to
15960 * add custom toolbar buttons.
15961 * @param {HtmlEditor} editor
15963 createToolbar : function(){
15965 Roo.log("create toolbars");
15967 this.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard({editor: this} ) ];
15968 this.toolbars[0].render(this.toolbarContainer());
15972 // if (!editor.toolbars || !editor.toolbars.length) {
15973 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
15976 // for (var i =0 ; i < editor.toolbars.length;i++) {
15977 // editor.toolbars[i] = Roo.factory(
15978 // typeof(editor.toolbars[i]) == 'string' ?
15979 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
15980 // Roo.bootstrap.HtmlEditor);
15981 // editor.toolbars[i].init(editor);
15987 onRender : function(ct, position)
15989 // Roo.log("Call onRender: " + this.xtype);
15991 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
15993 this.wrap = this.inputEl().wrap({
15994 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
15997 this.editorcore.onRender(ct, position);
15999 if (this.resizable) {
16000 this.resizeEl = new Roo.Resizable(this.wrap, {
16004 minHeight : this.height,
16005 height: this.height,
16006 handles : this.resizable,
16009 resize : function(r, w, h) {
16010 _t.onResize(w,h); // -something
16016 this.createToolbar(this);
16019 if(!this.width && this.resizable){
16020 this.setSize(this.wrap.getSize());
16022 if (this.resizeEl) {
16023 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
16024 // should trigger onReize..
16030 onResize : function(w, h)
16032 Roo.log('resize: ' +w + ',' + h );
16033 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
16037 if(this.inputEl() ){
16038 if(typeof w == 'number'){
16039 var aw = w - this.wrap.getFrameWidth('lr');
16040 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
16043 if(typeof h == 'number'){
16044 var tbh = -11; // fixme it needs to tool bar size!
16045 for (var i =0; i < this.toolbars.length;i++) {
16046 // fixme - ask toolbars for heights?
16047 tbh += this.toolbars[i].el.getHeight();
16048 //if (this.toolbars[i].footer) {
16049 // tbh += this.toolbars[i].footer.el.getHeight();
16057 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
16058 ah -= 5; // knock a few pixes off for look..
16059 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
16063 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
16064 this.editorcore.onResize(ew,eh);
16069 * Toggles the editor between standard and source edit mode.
16070 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16072 toggleSourceEdit : function(sourceEditMode)
16074 this.editorcore.toggleSourceEdit(sourceEditMode);
16076 if(this.editorcore.sourceEditMode){
16077 Roo.log('editor - showing textarea');
16080 // Roo.log(this.syncValue());
16082 this.inputEl().removeClass('hide');
16083 this.inputEl().dom.removeAttribute('tabIndex');
16084 this.inputEl().focus();
16086 Roo.log('editor - hiding textarea');
16088 // Roo.log(this.pushValue());
16091 this.inputEl().addClass('hide');
16092 this.inputEl().dom.setAttribute('tabIndex', -1);
16093 //this.deferFocus();
16096 if(this.resizable){
16097 this.setSize(this.wrap.getSize());
16100 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
16103 // private (for BoxComponent)
16104 adjustSize : Roo.BoxComponent.prototype.adjustSize,
16106 // private (for BoxComponent)
16107 getResizeEl : function(){
16111 // private (for BoxComponent)
16112 getPositionEl : function(){
16117 initEvents : function(){
16118 this.originalValue = this.getValue();
16122 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
16125 // markInvalid : Roo.emptyFn,
16127 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
16130 // clearInvalid : Roo.emptyFn,
16132 setValue : function(v){
16133 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
16134 this.editorcore.pushValue();
16139 deferFocus : function(){
16140 this.focus.defer(10, this);
16144 focus : function(){
16145 this.editorcore.focus();
16151 onDestroy : function(){
16157 for (var i =0; i < this.toolbars.length;i++) {
16158 // fixme - ask toolbars for heights?
16159 this.toolbars[i].onDestroy();
16162 this.wrap.dom.innerHTML = '';
16163 this.wrap.remove();
16168 onFirstFocus : function(){
16169 //Roo.log("onFirstFocus");
16170 this.editorcore.onFirstFocus();
16171 for (var i =0; i < this.toolbars.length;i++) {
16172 this.toolbars[i].onFirstFocus();
16178 syncValue : function()
16180 this.editorcore.syncValue();
16183 pushValue : function()
16185 this.editorcore.pushValue();
16189 // hide stuff that is not compatible
16203 * @event specialkey
16207 * @cfg {String} fieldClass @hide
16210 * @cfg {String} focusClass @hide
16213 * @cfg {String} autoCreate @hide
16216 * @cfg {String} inputType @hide
16219 * @cfg {String} invalidClass @hide
16222 * @cfg {String} invalidText @hide
16225 * @cfg {String} msgFx @hide
16228 * @cfg {String} validateOnBlur @hide
16239 * @class Roo.bootstrap.HtmlEditorToolbar1
16244 new Roo.bootstrap.HtmlEditor({
16247 new Roo.bootstrap.HtmlEditorToolbar1({
16248 disable : { fonts: 1 , format: 1, ..., ... , ...],
16254 * @cfg {Object} disable List of elements to disable..
16255 * @cfg {Array} btns List of additional buttons.
16259 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
16262 Roo.bootstrap.HtmlEditor.ToolbarStandard = function(config)
16265 Roo.apply(this, config);
16267 // default disabled, based on 'good practice'..
16268 this.disable = this.disable || {};
16269 Roo.applyIf(this.disable, {
16272 specialElements : true
16274 Roo.bootstrap.HtmlEditor.ToolbarStandard.superclass.constructor.call(this, config);
16276 this.editor = config.editor;
16277 this.editorcore = config.editor.editorcore;
16279 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
16281 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
16282 // dont call parent... till later.
16284 Roo.extend(Roo.bootstrap.HtmlEditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
16290 editorcore : false,
16295 "h1","h2","h3","h4","h5","h6",
16297 "abbr", "acronym", "address", "cite", "samp", "var",
16301 onRender : function(ct, position)
16303 // Roo.log("Call onRender: " + this.xtype);
16305 Roo.bootstrap.HtmlEditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
16307 this.el.dom.style.marginBottom = '0';
16309 var editorcore = this.editorcore;
16310 var editor= this.editor;
16313 var btn = function(id,cmd , toggle, handler){
16315 var event = toggle ? 'toggle' : 'click';
16320 xns: Roo.bootstrap,
16323 enableToggle:toggle !== false,
16325 pressed : toggle ? false : null,
16328 a.listeners[toggle ? 'toggle' : 'click'] = function() {
16329 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
16338 xns: Roo.bootstrap,
16339 glyphicon : 'font',
16343 xns: Roo.bootstrap,
16347 Roo.each(this.formats, function(f) {
16348 style.menu.items.push({
16350 xns: Roo.bootstrap,
16351 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
16356 editorcore.insertTag(this.tagname);
16363 children.push(style);
16366 btn('bold',false,true);
16367 btn('italic',false,true);
16368 btn('align-left', 'justifyleft',true);
16369 btn('align-center', 'justifycenter',true);
16370 btn('align-right' , 'justifyright',true);
16371 btn('link', false, false, function(btn) {
16372 //Roo.log("create link?");
16373 var url = prompt(this.createLinkText, this.defaultLinkValue);
16374 if(url && url != 'http:/'+'/'){
16375 this.editorcore.relayCmd('createlink', url);
16378 btn('list','insertunorderedlist',true);
16379 btn('pencil', false,true, function(btn){
16382 this.toggleSourceEdit(btn.pressed);
16388 xns: Roo.bootstrap,
16393 xns: Roo.bootstrap,
16398 cog.menu.items.push({
16400 xns: Roo.bootstrap,
16401 html : Clean styles,
16406 editorcore.insertTag(this.tagname);
16415 this.xtype = 'NavSimplebar';
16417 for(var i=0;i< children.length;i++) {
16419 this.buttons.add(this.addxtypeChild(children[i]));
16423 editor.on('editorevent', this.updateToolbar, this);
16425 onBtnClick : function(id)
16427 this.editorcore.relayCmd(id);
16428 this.editorcore.focus();
16432 * Protected method that will not generally be called directly. It triggers
16433 * a toolbar update by reading the markup state of the current selection in the editor.
16435 updateToolbar: function(){
16437 if(!this.editorcore.activated){
16438 this.editor.onFirstFocus(); // is this neeed?
16442 var btns = this.buttons;
16443 var doc = this.editorcore.doc;
16444 btns.get('bold').setActive(doc.queryCommandState('bold'));
16445 btns.get('italic').setActive(doc.queryCommandState('italic'));
16446 //btns.get('underline').setActive(doc.queryCommandState('underline'));
16448 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
16449 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
16450 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
16452 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
16453 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
16456 var ans = this.editorcore.getAllAncestors();
16457 if (this.formatCombo) {
16460 var store = this.formatCombo.store;
16461 this.formatCombo.setValue("");
16462 for (var i =0; i < ans.length;i++) {
16463 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
16465 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
16473 // hides menus... - so this cant be on a menu...
16474 Roo.bootstrap.MenuMgr.hideAll();
16476 Roo.bootstrap.MenuMgr.hideAll();
16477 //this.editorsyncValue();
16479 onFirstFocus: function() {
16480 this.buttons.each(function(item){
16484 toggleSourceEdit : function(sourceEditMode){
16487 if(sourceEditMode){
16488 Roo.log("disabling buttons");
16489 this.buttons.each( function(item){
16490 if(item.cmd != 'pencil'){
16496 Roo.log("enabling buttons");
16497 if(this.editorcore.initialized){
16498 this.buttons.each( function(item){
16504 Roo.log("calling toggole on editor");
16505 // tell the editor that it's been pressed..
16506 this.editor.toggleSourceEdit(sourceEditMode);
16516 * @class Roo.bootstrap.Table.AbstractSelectionModel
16517 * @extends Roo.util.Observable
16518 * Abstract base class for grid SelectionModels. It provides the interface that should be
16519 * implemented by descendant classes. This class should not be directly instantiated.
16522 Roo.bootstrap.Table.AbstractSelectionModel = function(){
16523 this.locked = false;
16524 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
16528 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
16529 /** @ignore Called by the grid automatically. Do not call directly. */
16530 init : function(grid){
16536 * Locks the selections.
16539 this.locked = true;
16543 * Unlocks the selections.
16545 unlock : function(){
16546 this.locked = false;
16550 * Returns true if the selections are locked.
16551 * @return {Boolean}
16553 isLocked : function(){
16554 return this.locked;
16558 * @class Roo.bootstrap.Table.ColumnModel
16559 * @extends Roo.util.Observable
16560 * This is the default implementation of a ColumnModel used by the bootstrap table. It defines
16561 * the columns in the table.
16564 * @param {Object} config An Array of column config objects. See this class's
16565 * config objects for details.
16567 Roo.bootstrap.Table.ColumnModel = function(config){
16569 * The config passed into the constructor
16571 this.config = config;
16574 // if no id, create one
16575 // if the column does not have a dataIndex mapping,
16576 // map it to the order it is in the config
16577 for(var i = 0, len = config.length; i < len; i++){
16579 if(typeof c.dataIndex == "undefined"){
16582 if(typeof c.renderer == "string"){
16583 c.renderer = Roo.util.Format[c.renderer];
16585 if(typeof c.id == "undefined"){
16588 // if(c.editor && c.editor.xtype){
16589 // c.editor = Roo.factory(c.editor, Roo.grid);
16591 // if(c.editor && c.editor.isFormField){
16592 // c.editor = new Roo.grid.GridEditor(c.editor);
16595 this.lookup[c.id] = c;
16599 * The width of columns which have no width specified (defaults to 100)
16602 this.defaultWidth = 100;
16605 * Default sortable of columns which have no sortable specified (defaults to false)
16608 this.defaultSortable = false;
16612 * @event widthchange
16613 * Fires when the width of a column changes.
16614 * @param {ColumnModel} this
16615 * @param {Number} columnIndex The column index
16616 * @param {Number} newWidth The new width
16618 "widthchange": true,
16620 * @event headerchange
16621 * Fires when the text of a header changes.
16622 * @param {ColumnModel} this
16623 * @param {Number} columnIndex The column index
16624 * @param {Number} newText The new header text
16626 "headerchange": true,
16628 * @event hiddenchange
16629 * Fires when a column is hidden or "unhidden".
16630 * @param {ColumnModel} this
16631 * @param {Number} columnIndex The column index
16632 * @param {Boolean} hidden true if hidden, false otherwise
16634 "hiddenchange": true,
16636 * @event columnmoved
16637 * Fires when a column is moved.
16638 * @param {ColumnModel} this
16639 * @param {Number} oldIndex
16640 * @param {Number} newIndex
16642 "columnmoved" : true,
16644 * @event columlockchange
16645 * Fires when a column's locked state is changed
16646 * @param {ColumnModel} this
16647 * @param {Number} colIndex
16648 * @param {Boolean} locked true if locked
16650 "columnlockchange" : true
16652 Roo.bootstrap.Table.ColumnModel.superclass.constructor.call(this);
16654 Roo.extend(Roo.bootstrap.Table.ColumnModel, Roo.util.Observable, {
16656 * @cfg {String} header The header text to display in the Grid view.
16659 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
16660 * {@link Roo.data.Record} definition from which to draw the column's value. If not
16661 * specified, the column's index is used as an index into the Record's data Array.
16664 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
16665 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
16668 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
16669 * Defaults to the value of the {@link #defaultSortable} property.
16670 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
16673 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
16676 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
16679 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
16682 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
16685 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
16686 * given the cell's data value. See {@link #setRenderer}. If not specified, the
16687 * default renderer uses the raw data value.
16690 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
16694 * Returns the id of the column at the specified index.
16695 * @param {Number} index The column index
16696 * @return {String} the id
16698 getColumnId : function(index){
16699 return this.config[index].id;
16703 * Returns the column for a specified id.
16704 * @param {String} id The column id
16705 * @return {Object} the column
16707 getColumnById : function(id){
16708 return this.lookup[id];
16713 * Returns the column for a specified dataIndex.
16714 * @param {String} dataIndex The column dataIndex
16715 * @return {Object|Boolean} the column or false if not found
16717 getColumnByDataIndex: function(dataIndex){
16718 var index = this.findColumnIndex(dataIndex);
16719 return index > -1 ? this.config[index] : false;
16723 * Returns the index for a specified column id.
16724 * @param {String} id The column id
16725 * @return {Number} the index, or -1 if not found
16727 getIndexById : function(id){
16728 for(var i = 0, len = this.config.length; i < len; i++){
16729 if(this.config[i].id == id){
16737 * Returns the index for a specified column dataIndex.
16738 * @param {String} dataIndex The column dataIndex
16739 * @return {Number} the index, or -1 if not found
16742 findColumnIndex : function(dataIndex){
16743 for(var i = 0, len = this.config.length; i < len; i++){
16744 if(this.config[i].dataIndex == dataIndex){
16752 moveColumn : function(oldIndex, newIndex){
16753 var c = this.config[oldIndex];
16754 this.config.splice(oldIndex, 1);
16755 this.config.splice(newIndex, 0, c);
16756 this.dataMap = null;
16757 this.fireEvent("columnmoved", this, oldIndex, newIndex);
16760 isLocked : function(colIndex){
16761 return this.config[colIndex].locked === true;
16764 setLocked : function(colIndex, value, suppressEvent){
16765 if(this.isLocked(colIndex) == value){
16768 this.config[colIndex].locked = value;
16769 if(!suppressEvent){
16770 this.fireEvent("columnlockchange", this, colIndex, value);
16774 getTotalLockedWidth : function(){
16775 var totalWidth = 0;
16776 for(var i = 0; i < this.config.length; i++){
16777 if(this.isLocked(i) && !this.isHidden(i)){
16778 this.totalWidth += this.getColumnWidth(i);
16784 getLockedCount : function(){
16785 for(var i = 0, len = this.config.length; i < len; i++){
16786 if(!this.isLocked(i)){
16793 * Returns the number of columns.
16796 getColumnCount : function(visibleOnly){
16797 if(visibleOnly === true){
16799 for(var i = 0, len = this.config.length; i < len; i++){
16800 if(!this.isHidden(i)){
16806 return this.config.length;
16810 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
16811 * @param {Function} fn
16812 * @param {Object} scope (optional)
16813 * @return {Array} result
16815 getColumnsBy : function(fn, scope){
16817 for(var i = 0, len = this.config.length; i < len; i++){
16818 var c = this.config[i];
16819 if(fn.call(scope||this, c, i) === true){
16827 * Returns true if the specified column is sortable.
16828 * @param {Number} col The column index
16829 * @return {Boolean}
16831 isSortable : function(col){
16832 if(typeof this.config[col].sortable == "undefined"){
16833 return this.defaultSortable;
16835 return this.config[col].sortable;
16839 * Returns the rendering (formatting) function defined for the column.
16840 * @param {Number} col The column index.
16841 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
16843 getRenderer : function(col){
16844 if(!this.config[col].renderer){
16845 return Roo.bootstrap.Table.ColumnModel.defaultRenderer;
16847 return this.config[col].renderer;
16851 * Sets the rendering (formatting) function for a column.
16852 * @param {Number} col The column index
16853 * @param {Function} fn The function to use to process the cell's raw data
16854 * to return HTML markup for the grid view. The render function is called with
16855 * the following parameters:<ul>
16856 * <li>Data value.</li>
16857 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
16858 * <li>css A CSS style string to apply to the table cell.</li>
16859 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
16860 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
16861 * <li>Row index</li>
16862 * <li>Column index</li>
16863 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
16865 setRenderer : function(col, fn){
16866 this.config[col].renderer = fn;
16870 * Returns the width for the specified column.
16871 * @param {Number} col The column index
16874 getColumnWidth : function(col){
16875 return this.config[col].width * 1 || this.defaultWidth;
16879 * Sets the width for a column.
16880 * @param {Number} col The column index
16881 * @param {Number} width The new width
16883 setColumnWidth : function(col, width, suppressEvent){
16884 this.config[col].width = width;
16885 this.totalWidth = null;
16886 if(!suppressEvent){
16887 this.fireEvent("widthchange", this, col, width);
16892 * Returns the total width of all columns.
16893 * @param {Boolean} includeHidden True to include hidden column widths
16896 getTotalWidth : function(includeHidden){
16897 if(!this.totalWidth){
16898 this.totalWidth = 0;
16899 for(var i = 0, len = this.config.length; i < len; i++){
16900 if(includeHidden || !this.isHidden(i)){
16901 this.totalWidth += this.getColumnWidth(i);
16905 return this.totalWidth;
16909 * Returns the header for the specified column.
16910 * @param {Number} col The column index
16913 getColumnHeader : function(col){
16914 return this.config[col].header;
16918 * Sets the header for a column.
16919 * @param {Number} col The column index
16920 * @param {String} header The new header
16922 setColumnHeader : function(col, header){
16923 this.config[col].header = header;
16924 this.fireEvent("headerchange", this, col, header);
16928 * Returns the tooltip for the specified column.
16929 * @param {Number} col The column index
16932 getColumnTooltip : function(col){
16933 return this.config[col].tooltip;
16936 * Sets the tooltip for a column.
16937 * @param {Number} col The column index
16938 * @param {String} tooltip The new tooltip
16940 setColumnTooltip : function(col, tooltip){
16941 this.config[col].tooltip = tooltip;
16945 * Returns the dataIndex for the specified column.
16946 * @param {Number} col The column index
16949 getDataIndex : function(col){
16950 return this.config[col].dataIndex;
16954 * Sets the dataIndex for a column.
16955 * @param {Number} col The column index
16956 * @param {Number} dataIndex The new dataIndex
16958 setDataIndex : function(col, dataIndex){
16959 this.config[col].dataIndex = dataIndex;
16965 * Returns true if the cell is editable.
16966 * @param {Number} colIndex The column index
16967 * @param {Number} rowIndex The row index
16968 * @return {Boolean}
16970 isCellEditable : function(colIndex, rowIndex){
16971 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
16975 * Returns the editor defined for the cell/column.
16976 * return false or null to disable editing.
16977 * @param {Number} colIndex The column index
16978 * @param {Number} rowIndex The row index
16981 getCellEditor : function(colIndex, rowIndex){
16982 return this.config[colIndex].editor;
16986 * Sets if a column is editable.
16987 * @param {Number} col The column index
16988 * @param {Boolean} editable True if the column is editable
16990 setEditable : function(col, editable){
16991 this.config[col].editable = editable;
16996 * Returns true if the column is hidden.
16997 * @param {Number} colIndex The column index
16998 * @return {Boolean}
17000 isHidden : function(colIndex){
17001 return this.config[colIndex].hidden;
17006 * Returns true if the column width cannot be changed
17008 isFixed : function(colIndex){
17009 return this.config[colIndex].fixed;
17013 * Returns true if the column can be resized
17014 * @return {Boolean}
17016 isResizable : function(colIndex){
17017 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
17020 * Sets if a column is hidden.
17021 * @param {Number} colIndex The column index
17022 * @param {Boolean} hidden True if the column is hidden
17024 setHidden : function(colIndex, hidden){
17025 this.config[colIndex].hidden = hidden;
17026 this.totalWidth = null;
17027 this.fireEvent("hiddenchange", this, colIndex, hidden);
17031 * Sets the editor for a column.
17032 * @param {Number} col The column index
17033 * @param {Object} editor The editor object
17035 setEditor : function(col, editor){
17036 this.config[col].editor = editor;
17040 Roo.bootstrap.Table.ColumnModel.defaultRenderer = function(value){
17041 if(typeof value == "string" && value.length < 1){
17047 // Alias for backwards compatibility
17048 Roo.bootstrap.Table.DefaultColumnModel = Roo.bootstrap.Table.ColumnModel;
17051 * @extends Roo.bootstrap.Table.AbstractSelectionModel
17052 * @class Roo.bootstrap.Table.RowSelectionModel
17053 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
17054 * It supports multiple selections and keyboard selection/navigation.
17056 * @param {Object} config
17059 Roo.bootstrap.Table.RowSelectionModel = function(config){
17060 Roo.apply(this, config);
17061 this.selections = new Roo.util.MixedCollection(false, function(o){
17066 this.lastActive = false;
17070 * @event selectionchange
17071 * Fires when the selection changes
17072 * @param {SelectionModel} this
17074 "selectionchange" : true,
17076 * @event afterselectionchange
17077 * Fires after the selection changes (eg. by key press or clicking)
17078 * @param {SelectionModel} this
17080 "afterselectionchange" : true,
17082 * @event beforerowselect
17083 * Fires when a row is selected being selected, return false to cancel.
17084 * @param {SelectionModel} this
17085 * @param {Number} rowIndex The selected index
17086 * @param {Boolean} keepExisting False if other selections will be cleared
17088 "beforerowselect" : true,
17091 * Fires when a row is selected.
17092 * @param {SelectionModel} this
17093 * @param {Number} rowIndex The selected index
17094 * @param {Roo.data.Record} r The record
17096 "rowselect" : true,
17098 * @event rowdeselect
17099 * Fires when a row is deselected.
17100 * @param {SelectionModel} this
17101 * @param {Number} rowIndex The selected index
17103 "rowdeselect" : true
17105 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
17106 this.locked = false;
17109 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
17111 * @cfg {Boolean} singleSelect
17112 * True to allow selection of only one row at a time (defaults to false)
17114 singleSelect : false,
17117 initEvents : function(){
17119 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
17120 this.grid.on("mousedown", this.handleMouseDown, this);
17121 }else{ // allow click to work like normal
17122 this.grid.on("rowclick", this.handleDragableRowClick, this);
17125 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
17126 "up" : function(e){
17128 this.selectPrevious(e.shiftKey);
17129 }else if(this.last !== false && this.lastActive !== false){
17130 var last = this.last;
17131 this.selectRange(this.last, this.lastActive-1);
17132 this.grid.getView().focusRow(this.lastActive);
17133 if(last !== false){
17137 this.selectFirstRow();
17139 this.fireEvent("afterselectionchange", this);
17141 "down" : function(e){
17143 this.selectNext(e.shiftKey);
17144 }else if(this.last !== false && this.lastActive !== false){
17145 var last = this.last;
17146 this.selectRange(this.last, this.lastActive+1);
17147 this.grid.getView().focusRow(this.lastActive);
17148 if(last !== false){
17152 this.selectFirstRow();
17154 this.fireEvent("afterselectionchange", this);
17159 var view = this.grid.view;
17160 view.on("refresh", this.onRefresh, this);
17161 view.on("rowupdated", this.onRowUpdated, this);
17162 view.on("rowremoved", this.onRemove, this);
17166 onRefresh : function(){
17167 var ds = this.grid.dataSource, i, v = this.grid.view;
17168 var s = this.selections;
17169 s.each(function(r){
17170 if((i = ds.indexOfId(r.id)) != -1){
17179 onRemove : function(v, index, r){
17180 this.selections.remove(r);
17184 onRowUpdated : function(v, index, r){
17185 if(this.isSelected(r)){
17186 v.onRowSelect(index);
17192 * @param {Array} records The records to select
17193 * @param {Boolean} keepExisting (optional) True to keep existing selections
17195 selectRecords : function(records, keepExisting){
17197 this.clearSelections();
17199 var ds = this.grid.dataSource;
17200 for(var i = 0, len = records.length; i < len; i++){
17201 this.selectRow(ds.indexOf(records[i]), true);
17206 * Gets the number of selected rows.
17209 getCount : function(){
17210 return this.selections.length;
17214 * Selects the first row in the grid.
17216 selectFirstRow : function(){
17221 * Select the last row.
17222 * @param {Boolean} keepExisting (optional) True to keep existing selections
17224 selectLastRow : function(keepExisting){
17225 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
17229 * Selects the row immediately following the last selected row.
17230 * @param {Boolean} keepExisting (optional) True to keep existing selections
17232 selectNext : function(keepExisting){
17233 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
17234 this.selectRow(this.last+1, keepExisting);
17235 this.grid.getView().focusRow(this.last);
17240 * Selects the row that precedes the last selected row.
17241 * @param {Boolean} keepExisting (optional) True to keep existing selections
17243 selectPrevious : function(keepExisting){
17245 this.selectRow(this.last-1, keepExisting);
17246 this.grid.getView().focusRow(this.last);
17251 * Returns the selected records
17252 * @return {Array} Array of selected records
17254 getSelections : function(){
17255 return [].concat(this.selections.items);
17259 * Returns the first selected record.
17262 getSelected : function(){
17263 return this.selections.itemAt(0);
17268 * Clears all selections.
17270 clearSelections : function(fast){
17271 if(this.locked) return;
17273 var ds = this.grid.dataSource;
17274 var s = this.selections;
17275 s.each(function(r){
17276 this.deselectRow(ds.indexOfId(r.id));
17280 this.selections.clear();
17287 * Selects all rows.
17289 selectAll : function(){
17290 if(this.locked) return;
17291 this.selections.clear();
17292 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
17293 this.selectRow(i, true);
17298 * Returns True if there is a selection.
17299 * @return {Boolean}
17301 hasSelection : function(){
17302 return this.selections.length > 0;
17306 * Returns True if the specified row is selected.
17307 * @param {Number/Record} record The record or index of the record to check
17308 * @return {Boolean}
17310 isSelected : function(index){
17311 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
17312 return (r && this.selections.key(r.id) ? true : false);
17316 * Returns True if the specified record id is selected.
17317 * @param {String} id The id of record to check
17318 * @return {Boolean}
17320 isIdSelected : function(id){
17321 return (this.selections.key(id) ? true : false);
17325 handleMouseDown : function(e, t){
17326 var view = this.grid.getView(), rowIndex;
17327 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
17330 if(e.shiftKey && this.last !== false){
17331 var last = this.last;
17332 this.selectRange(last, rowIndex, e.ctrlKey);
17333 this.last = last; // reset the last
17334 view.focusRow(rowIndex);
17336 var isSelected = this.isSelected(rowIndex);
17337 if(e.button !== 0 && isSelected){
17338 view.focusRow(rowIndex);
17339 }else if(e.ctrlKey && isSelected){
17340 this.deselectRow(rowIndex);
17341 }else if(!isSelected){
17342 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
17343 view.focusRow(rowIndex);
17346 this.fireEvent("afterselectionchange", this);
17349 handleDragableRowClick : function(grid, rowIndex, e)
17351 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
17352 this.selectRow(rowIndex, false);
17353 grid.view.focusRow(rowIndex);
17354 this.fireEvent("afterselectionchange", this);
17359 * Selects multiple rows.
17360 * @param {Array} rows Array of the indexes of the row to select
17361 * @param {Boolean} keepExisting (optional) True to keep existing selections
17363 selectRows : function(rows, keepExisting){
17365 this.clearSelections();
17367 for(var i = 0, len = rows.length; i < len; i++){
17368 this.selectRow(rows[i], true);
17373 * Selects a range of rows. All rows in between startRow and endRow are also selected.
17374 * @param {Number} startRow The index of the first row in the range
17375 * @param {Number} endRow The index of the last row in the range
17376 * @param {Boolean} keepExisting (optional) True to retain existing selections
17378 selectRange : function(startRow, endRow, keepExisting){
17379 if(this.locked) return;
17381 this.clearSelections();
17383 if(startRow <= endRow){
17384 for(var i = startRow; i <= endRow; i++){
17385 this.selectRow(i, true);
17388 for(var i = startRow; i >= endRow; i--){
17389 this.selectRow(i, true);
17395 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
17396 * @param {Number} startRow The index of the first row in the range
17397 * @param {Number} endRow The index of the last row in the range
17399 deselectRange : function(startRow, endRow, preventViewNotify){
17400 if(this.locked) return;
17401 for(var i = startRow; i <= endRow; i++){
17402 this.deselectRow(i, preventViewNotify);
17408 * @param {Number} row The index of the row to select
17409 * @param {Boolean} keepExisting (optional) True to keep existing selections
17411 selectRow : function(index, keepExisting, preventViewNotify){
17412 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
17413 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
17414 if(!keepExisting || this.singleSelect){
17415 this.clearSelections();
17417 var r = this.grid.dataSource.getAt(index);
17418 this.selections.add(r);
17419 this.last = this.lastActive = index;
17420 if(!preventViewNotify){
17421 this.grid.getView().onRowSelect(index);
17423 this.fireEvent("rowselect", this, index, r);
17424 this.fireEvent("selectionchange", this);
17430 * @param {Number} row The index of the row to deselect
17432 deselectRow : function(index, preventViewNotify){
17433 if(this.locked) return;
17434 if(this.last == index){
17437 if(this.lastActive == index){
17438 this.lastActive = false;
17440 var r = this.grid.dataSource.getAt(index);
17441 this.selections.remove(r);
17442 if(!preventViewNotify){
17443 this.grid.getView().onRowDeselect(index);
17445 this.fireEvent("rowdeselect", this, index);
17446 this.fireEvent("selectionchange", this);
17450 restoreLast : function(){
17452 this.last = this._last;
17457 acceptsNav : function(row, col, cm){
17458 return !cm.isHidden(col) && cm.isCellEditable(col, row);
17462 onEditorKey : function(field, e){
17463 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
17468 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
17470 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
17472 }else if(k == e.ENTER && !e.ctrlKey){
17476 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
17478 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
17480 }else if(k == e.ESC){
17484 g.startEditing(newCell[0], newCell[1]);
17495 * @class Roo.bootstrap.MessageBar
17496 * @extends Roo.bootstrap.Component
17497 * Bootstrap MessageBar class
17498 * @cfg {String} html contents of the MessageBar
17499 * @cfg {String} weight (info | success | warning | danger) default info
17500 * @cfg {String} beforeClass insert the bar before the given class
17501 * @cfg {Boolean} closable (true | false) default false
17502 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
17505 * Create a new Element
17506 * @param {Object} config The config object
17509 Roo.bootstrap.MessageBar = function(config){
17510 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
17513 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
17519 beforeClass: 'bootstrap-sticky-wrap',
17521 getAutoCreate : function(){
17525 cls: 'alert alert-dismissable alert-' + this.weight,
17530 html: this.html || ''
17536 cfg.cls += ' alert-messages-fixed';
17550 onRender : function(ct, position)
17552 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17555 var cfg = Roo.apply({}, this.getAutoCreate());
17559 cfg.cls += ' ' + this.cls;
17562 cfg.style = this.style;
17564 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
17566 this.el.setVisibilityMode(Roo.Element.DISPLAY);
17569 this.el.select('>button.close').on('click', this.hide, this);
17575 if (!this.rendered) {
17581 this.fireEvent('show', this);
17587 if (!this.rendered) {
17593 this.fireEvent('hide', this);
17596 update : function()
17598 // var e = this.el.dom.firstChild;
17600 // if(this.closable){
17601 // e = e.nextSibling;
17604 // e.data = this.html || '';
17606 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';