4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
21 * Do not use directly - it does not do anything..
22 * @param {Object} config The config object
27 Roo.bootstrap.Component = function(config){
28 Roo.bootstrap.Component.superclass.constructor.call(this, config);
31 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
34 allowDomMove : false, // to stop relocations in parent onRender...
42 initEvents : function() { },
48 can_build_overlaid : true,
55 // returns the parent component..
56 return Roo.ComponentMgr.get(this.parentId)
62 onRender : function(ct, position)
64 // Roo.log("Call onRender: " + this.xtype);
66 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
69 if (this.el.attr('xtype')) {
70 this.el.attr('xtypex', this.el.attr('xtype'));
71 this.el.dom.removeAttribute('xtype');
81 var cfg = Roo.apply({}, this.getAutoCreate());
84 // fill in the extra attributes
85 if (this.xattr && typeof(this.xattr) =='object') {
86 for (var i in this.xattr) {
87 cfg[i] = this.xattr[i];
92 cfg.dataId = this.dataId;
96 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
99 if (this.style) { // fixme needs to support more complex style data.
100 cfg.style = this.style;
104 cfg.name = this.name;
107 this.el = ct.createChild(cfg, position);
109 if(this.tabIndex !== undefined){
110 this.el.dom.setAttribute('tabIndex', this.tabIndex);
117 getChildContainer : function()
123 addxtype : function(tree,cntr)
127 cn = Roo.factory(tree);
129 cn.parentType = this.xtype; //??
130 cn.parentId = this.id;
132 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
134 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
136 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
138 var build_from_html = Roo.XComponent.build_from_html;
140 var is_body = (tree.xtype == 'Body') ;
142 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
144 var self_cntr_el = Roo.get(this[cntr](false));
146 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
147 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
148 return this.addxtypeChild(tree,cntr);
151 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
154 return this.addxtypeChild(Roo.apply({}, tree),cntr);
157 Roo.log('skipping render');
165 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
171 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
175 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
180 addxtypeChild : function (tree, cntr)
182 Roo.log('addxtypeChild:' + cntr);
184 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
187 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
188 (typeof(tree['flexy:foreach']) != 'undefined');
193 // render the element if it's not BODY.
194 if (tree.xtype != 'Body') {
196 cn = Roo.factory(tree);
198 cn.parentType = this.xtype; //??
199 cn.parentId = this.id;
201 var build_from_html = Roo.XComponent.build_from_html;
204 // does the container contain child eleemnts with 'xtype' attributes.
205 // that match this xtype..
206 // note - when we render we create these as well..
207 // so we should check to see if body has xtype set.
208 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
210 var self_cntr_el = Roo.get(this[cntr](false));
211 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
213 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
214 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
220 //echild.dom.removeAttribute('xtype');
222 Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
229 // if object has flexy:if - then it may or may not be rendered.
230 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
231 // skip a flexy if element.
232 Roo.log('skipping render');
235 // actually if flexy:foreach is found, we really want to create
236 // multiple copies here...
238 //Roo.log(this[cntr]());
239 cn.render(this[cntr](true));
241 // then add the element..
249 if (typeof (tree.menu) != 'undefined') {
250 tree.menu.parentType = cn.xtype;
251 tree.menu.triggerEl = cn.el;
252 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
256 if (!tree.items || !tree.items.length) {
260 var items = tree.items;
263 //Roo.log(items.length);
265 for(var i =0;i < items.length;i++) {
266 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
287 * @class Roo.bootstrap.Body
288 * @extends Roo.bootstrap.Component
289 * Bootstrap Body class
293 * @param {Object} config The config object
296 Roo.bootstrap.Body = function(config){
297 Roo.bootstrap.Body.superclass.constructor.call(this, config);
298 this.el = Roo.get(document.body);
299 if (this.cls && this.cls.length) {
300 Roo.get(document.body).addClass(this.cls);
304 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
309 onRender : function(ct, position)
311 /* Roo.log("Roo.bootstrap.Body - onRender");
312 if (this.cls && this.cls.length) {
313 Roo.get(document.body).addClass(this.cls);
333 * @class Roo.bootstrap.ButtonGroup
334 * @extends Roo.bootstrap.Component
335 * Bootstrap ButtonGroup class
336 * @cfg {String} size lg | sm | xs (default empty normal)
337 * @cfg {String} align vertical | justified (default none)
338 * @cfg {String} direction up | down (default down)
339 * @cfg {Boolean} toolbar false | true
340 * @cfg {Boolean} btn true | false
345 * @param {Object} config The config object
348 Roo.bootstrap.ButtonGroup = function(config){
349 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
352 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
360 getAutoCreate : function(){
366 cfg.html = this.html || cfg.html;
377 if (['vertical','justified'].indexOf(this.align)!==-1) {
378 cfg.cls = 'btn-group-' + this.align;
380 if (this.align == 'justified') {
381 console.log(this.items);
385 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
386 cfg.cls += ' btn-group-' + this.size;
389 if (this.direction == 'up') {
390 cfg.cls += ' dropup' ;
406 * @class Roo.bootstrap.Button
407 * @extends Roo.bootstrap.Component
408 * Bootstrap Button class
409 * @cfg {String} html The button content
410 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger | link
411 * @cfg {String} size empty | lg | sm | xs
412 * @cfg {String} tag empty | a | input | submit
413 * @cfg {String} href empty or href
414 * @cfg {Boolean} disabled false | true
415 * @cfg {Boolean} isClose false | true
416 * @cfg {String} glyphicon empty | adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out
417 * @cfg {String} badge text for badge
418 * @cfg {String} theme default (or empty) | glow
419 * @cfg {Boolean} inverse false | true
420 * @cfg {Boolean} toggle false | true
421 * @cfg {String} ontext text for on toggle state
422 * @cfg {String} offtext text for off toggle state
423 * @cfg {Boolean} defaulton true | false
424 * @cfg {Boolean} preventDefault (true | false) default true
425 * @cfg {Boolean} removeClass true | false remove the standard class..
426 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
429 * Create a new button
430 * @param {Object} config The config object
434 Roo.bootstrap.Button = function(config){
435 Roo.bootstrap.Button.superclass.constructor.call(this, config);
440 * When a butotn is pressed
441 * @param {Roo.EventObject} e
446 * After the button has been toggles
447 * @param {Roo.EventObject} e
448 * @param {boolean} pressed (also available as button.pressed)
454 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
472 preventDefault: true,
481 getAutoCreate : function(){
489 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
490 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
495 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
497 if (this.toggle == true) {
500 cls: 'slider-frame roo-button',
505 'data-off-text':'OFF',
506 cls: 'slider-button',
512 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
513 cfg.cls += ' '+this.weight;
522 cfg["aria-hidden"] = true;
524 cfg.html = "×";
530 if (this.theme==='default') {
531 cfg.cls = 'btn roo-button';
533 //if (this.parentType != 'Navbar') {
534 this.weight = this.weight.length ? this.weight : 'default';
536 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
538 cfg.cls += ' btn-' + this.weight;
540 } else if (this.theme==='glow') {
543 cfg.cls = 'btn-glow roo-button';
545 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
547 cfg.cls += ' ' + this.weight;
553 this.cls += ' inverse';
558 cfg.cls += ' active';
562 cfg.disabled = 'disabled';
566 Roo.log('changing to ul' );
568 this.glyphicon = 'caret';
571 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
573 //gsRoo.log(this.parentType);
574 if (this.parentType === 'Navbar' && !this.parent().bar) {
575 Roo.log('changing to li?');
584 href : this.href || '#'
587 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
588 cfg.cls += ' dropdown';
595 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
597 if (this.glyphicon) {
598 cfg.html = ' ' + cfg.html;
603 cls: 'glyphicon glyphicon-' + this.glyphicon
613 // cfg.cls='btn roo-button';
617 var value = cfg.html;
622 cls: 'glyphicon glyphicon-' + this.glyphicon,
641 cfg.cls += ' dropdown';
642 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
645 if (cfg.tag !== 'a' && this.href !== '') {
646 throw "Tag must be a to set href.";
647 } else if (this.href.length > 0) {
648 cfg.href = this.href;
651 if(this.removeClass){
656 cfg.target = this.target;
661 initEvents: function() {
662 // Roo.log('init events?');
663 // Roo.log(this.el.dom);
666 if (typeof (this.menu) != 'undefined') {
667 this.menu.parentType = this.xtype;
668 this.menu.triggerEl = this.el;
669 this.addxtype(Roo.apply({}, this.menu));
673 if (this.el.hasClass('roo-button')) {
674 this.el.on('click', this.onClick, this);
676 this.el.select('.roo-button').on('click', this.onClick, this);
679 if(this.removeClass){
680 this.el.on('click', this.onClick, this);
683 this.el.enableDisplayMode();
686 onClick : function(e)
692 Roo.log('button on click ');
693 if(this.preventDefault){
696 if (this.pressed === true || this.pressed === false) {
697 this.pressed = !this.pressed;
698 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
699 this.fireEvent('toggle', this, e, this.pressed);
703 this.fireEvent('click', this, e);
707 * Enables this button
711 this.disabled = false;
712 this.el.removeClass('disabled');
716 * Disable this button
720 this.disabled = true;
721 this.el.addClass('disabled');
724 * sets the active state on/off,
725 * @param {Boolean} state (optional) Force a particular state
727 setActive : function(v) {
729 this.el[v ? 'addClass' : 'removeClass']('active');
732 * toggles the current active state
734 toggleActive : function()
736 var active = this.el.hasClass('active');
737 this.setActive(!active);
741 setText : function(str)
743 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
747 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
770 * @class Roo.bootstrap.Column
771 * @extends Roo.bootstrap.Component
772 * Bootstrap Column class
773 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
774 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
775 * @cfg {Number} md colspan out of 12 for computer-sized screens
776 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
777 * @cfg {String} html content of column.
780 * Create a new Column
781 * @param {Object} config The config object
784 Roo.bootstrap.Column = function(config){
785 Roo.bootstrap.Column.superclass.constructor.call(this, config);
788 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
797 getAutoCreate : function(){
798 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
806 ['xs','sm','md','lg'].map(function(size){
807 if (settings[size]) {
808 cfg.cls += ' col-' + size + '-' + settings[size];
811 if (this.html.length) {
812 cfg.html = this.html;
831 * @class Roo.bootstrap.Container
832 * @extends Roo.bootstrap.Component
833 * Bootstrap Container class
834 * @cfg {Boolean} jumbotron is it a jumbotron element
835 * @cfg {String} html content of element
836 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
837 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
838 * @cfg {String} header content of header (for panel)
839 * @cfg {String} footer content of footer (for panel)
840 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
841 * @cfg {String} tag (header|aside|section) type of HTML tag.
845 * Create a new Container
846 * @param {Object} config The config object
849 Roo.bootstrap.Container = function(config){
850 Roo.bootstrap.Container.superclass.constructor.call(this, config);
853 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
864 getChildContainer : function() {
870 if (this.panel.length) {
871 return this.el.select('.panel-body',true).first();
878 getAutoCreate : function(){
881 tag : this.tag || 'div',
885 if (this.jumbotron) {
886 cfg.cls = 'jumbotron';
888 // - this is applied by the parent..
890 // cfg.cls = this.cls + '';
893 if (this.sticky.length) {
895 var bd = Roo.get(document.body);
896 if (!bd.hasClass('bootstrap-sticky')) {
897 bd.addClass('bootstrap-sticky');
898 Roo.select('html',true).setStyle('height', '100%');
901 cfg.cls += 'bootstrap-sticky-' + this.sticky;
905 if (this.well.length) {
909 cfg.cls +=' well well-' +this.well;
919 if (this.panel.length) {
920 cfg.cls += ' panel panel-' + this.panel;
922 if (this.header.length) {
925 cls : 'panel-heading',
941 if (this.footer.length) {
943 cls : 'panel-footer',
952 body.html = this.html || cfg.html;
954 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
955 cfg.cls = 'container';
972 * @class Roo.bootstrap.Img
973 * @extends Roo.bootstrap.Component
974 * Bootstrap Img class
975 * @cfg {Boolean} imgResponsive false | true
976 * @cfg {String} border rounded | circle | thumbnail
977 * @cfg {String} src image source
978 * @cfg {String} alt image alternative text
979 * @cfg {String} href a tag href
980 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
984 * @param {Object} config The config object
987 Roo.bootstrap.Img = function(config){
988 Roo.bootstrap.Img.superclass.constructor.call(this, config);
994 * The img click event for the img.
995 * @param {Roo.EventObject} e
1001 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1003 imgResponsive: true,
1009 getAutoCreate : function(){
1013 cls: (this.imgResponsive) ? 'img-responsive' : '',
1017 cfg.html = this.html || cfg.html;
1019 cfg.src = this.src || cfg.src;
1021 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1022 cfg.cls += ' img-' + this.border;
1039 a.target = this.target;
1045 return (this.href) ? a : cfg;
1048 initEvents: function() {
1051 this.el.on('click', this.onClick, this);
1055 onClick : function(e)
1057 Roo.log('img onclick');
1058 this.fireEvent('click', this, e);
1072 * @class Roo.bootstrap.Link
1073 * @extends Roo.bootstrap.Component
1074 * Bootstrap Link Class
1075 * @cfg {String} alt image alternative text
1076 * @cfg {String} href a tag href
1077 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1078 * @cfg {String} html the content of the link.
1082 * Create a new Input
1083 * @param {Object} config The config object
1086 Roo.bootstrap.Link = function(config){
1087 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1093 * The img click event for the img.
1094 * @param {Roo.EventObject} e
1100 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1105 getAutoCreate : function(){
1109 html : this.html || 'html-missing'
1116 cfg.href = this.href || '#';
1118 cfg.target = this.target;
1124 initEvents: function() {
1127 this.el.on('click', this.onClick, this);
1131 onClick : function(e)
1133 //Roo.log('img onclick');
1134 this.fireEvent('click', this, e);
1147 * @class Roo.bootstrap.Header
1148 * @extends Roo.bootstrap.Component
1149 * Bootstrap Header class
1150 * @cfg {String} html content of header
1151 * @cfg {Number} level (1|2|3|4|5|6) default 1
1154 * Create a new Header
1155 * @param {Object} config The config object
1159 Roo.bootstrap.Header = function(config){
1160 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1163 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1171 getAutoCreate : function(){
1174 tag: 'h' + (1 *this.level),
1175 html: this.html || 'fill in html'
1187 * Ext JS Library 1.1.1
1188 * Copyright(c) 2006-2007, Ext JS, LLC.
1190 * Originally Released Under LGPL - original licence link has changed is not relivant.
1193 * <script type="text/javascript">
1197 * @class Roo.bootstrap.MenuMgr
1198 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1201 Roo.bootstrap.MenuMgr = function(){
1202 var menus, active, groups = {}, attached = false, lastShow = new Date();
1204 // private - called when first menu is created
1207 active = new Roo.util.MixedCollection();
1208 Roo.get(document).addKeyListener(27, function(){
1209 if(active.length > 0){
1217 if(active && active.length > 0){
1218 var c = active.clone();
1228 if(active.length < 1){
1229 Roo.get(document).un("mouseup", onMouseDown);
1237 var last = active.last();
1238 lastShow = new Date();
1241 Roo.get(document).on("mouseup", onMouseDown);
1246 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1247 m.parentMenu.activeChild = m;
1248 }else if(last && last.isVisible()){
1249 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1254 function onBeforeHide(m){
1256 m.activeChild.hide();
1258 if(m.autoHideTimer){
1259 clearTimeout(m.autoHideTimer);
1260 delete m.autoHideTimer;
1265 function onBeforeShow(m){
1266 var pm = m.parentMenu;
1267 if(!pm && !m.allowOtherMenus){
1269 }else if(pm && pm.activeChild && active != m){
1270 pm.activeChild.hide();
1275 function onMouseDown(e){
1276 Roo.log("on MouseDown");
1277 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1285 function onBeforeCheck(mi, state){
1287 var g = groups[mi.group];
1288 for(var i = 0, l = g.length; i < l; i++){
1290 g[i].setChecked(false);
1299 * Hides all menus that are currently visible
1301 hideAll : function(){
1306 register : function(menu){
1310 menus[menu.id] = menu;
1311 menu.on("beforehide", onBeforeHide);
1312 menu.on("hide", onHide);
1313 menu.on("beforeshow", onBeforeShow);
1314 menu.on("show", onShow);
1316 if(g && menu.events["checkchange"]){
1320 groups[g].push(menu);
1321 menu.on("checkchange", onCheck);
1326 * Returns a {@link Roo.menu.Menu} object
1327 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1328 * be used to generate and return a new Menu instance.
1330 get : function(menu){
1331 if(typeof menu == "string"){ // menu id
1333 }else if(menu.events){ // menu instance
1336 /*else if(typeof menu.length == 'number'){ // array of menu items?
1337 return new Roo.bootstrap.Menu({items:menu});
1338 }else{ // otherwise, must be a config
1339 return new Roo.bootstrap.Menu(menu);
1346 unregister : function(menu){
1347 delete menus[menu.id];
1348 menu.un("beforehide", onBeforeHide);
1349 menu.un("hide", onHide);
1350 menu.un("beforeshow", onBeforeShow);
1351 menu.un("show", onShow);
1353 if(g && menu.events["checkchange"]){
1354 groups[g].remove(menu);
1355 menu.un("checkchange", onCheck);
1360 registerCheckable : function(menuItem){
1361 var g = menuItem.group;
1366 groups[g].push(menuItem);
1367 menuItem.on("beforecheckchange", onBeforeCheck);
1372 unregisterCheckable : function(menuItem){
1373 var g = menuItem.group;
1375 groups[g].remove(menuItem);
1376 menuItem.un("beforecheckchange", onBeforeCheck);
1388 * @class Roo.bootstrap.Menu
1389 * @extends Roo.bootstrap.Component
1390 * Bootstrap Menu class - container for MenuItems
1391 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1395 * @param {Object} config The config object
1399 Roo.bootstrap.Menu = function(config){
1400 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1401 if (this.registerMenu) {
1402 Roo.bootstrap.MenuMgr.register(this);
1407 * Fires before this menu is displayed
1408 * @param {Roo.menu.Menu} this
1413 * Fires before this menu is hidden
1414 * @param {Roo.menu.Menu} this
1419 * Fires after this menu is displayed
1420 * @param {Roo.menu.Menu} this
1425 * Fires after this menu is hidden
1426 * @param {Roo.menu.Menu} this
1431 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1432 * @param {Roo.menu.Menu} this
1433 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1434 * @param {Roo.EventObject} e
1439 * Fires when the mouse is hovering over this menu
1440 * @param {Roo.menu.Menu} this
1441 * @param {Roo.EventObject} e
1442 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1447 * Fires when the mouse exits this menu
1448 * @param {Roo.menu.Menu} this
1449 * @param {Roo.EventObject} e
1450 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1455 * Fires when a menu item contained in this menu is clicked
1456 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1457 * @param {Roo.EventObject} e
1461 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1464 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1468 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1471 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1473 registerMenu : true,
1475 menuItems :false, // stores the menu items..
1481 getChildContainer : function() {
1485 getAutoCreate : function(){
1487 //if (['right'].indexOf(this.align)!==-1) {
1488 // cfg.cn[1].cls += ' pull-right'
1494 cls : 'dropdown-menu' ,
1495 style : 'z-index:1000'
1499 if (this.type === 'submenu') {
1500 cfg.cls = 'submenu active';
1502 if (this.type === 'treeview') {
1503 cfg.cls = 'treeview-menu';
1508 initEvents : function() {
1510 // Roo.log("ADD event");
1511 // Roo.log(this.triggerEl.dom);
1512 this.triggerEl.on('click', this.onTriggerPress, this);
1513 this.triggerEl.addClass('dropdown-toggle');
1514 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1516 this.el.on("mouseover", this.onMouseOver, this);
1517 this.el.on("mouseout", this.onMouseOut, this);
1521 findTargetItem : function(e){
1522 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1526 //Roo.log(t); Roo.log(t.id);
1528 //Roo.log(this.menuitems);
1529 return this.menuitems.get(t.id);
1531 //return this.items.get(t.menuItemId);
1536 onClick : function(e){
1537 Roo.log("menu.onClick");
1538 var t = this.findTargetItem(e);
1544 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1545 if(t == this.activeItem && t.shouldDeactivate(e)){
1546 this.activeItem.deactivate();
1547 delete this.activeItem;
1551 this.setActiveItem(t, true);
1558 Roo.log('pass click event');
1562 this.fireEvent("click", this, t, e);
1566 onMouseOver : function(e){
1567 var t = this.findTargetItem(e);
1570 // if(t.canActivate && !t.disabled){
1571 // this.setActiveItem(t, true);
1575 this.fireEvent("mouseover", this, e, t);
1577 isVisible : function(){
1578 return !this.hidden;
1580 onMouseOut : function(e){
1581 var t = this.findTargetItem(e);
1584 // if(t == this.activeItem && t.shouldDeactivate(e)){
1585 // this.activeItem.deactivate();
1586 // delete this.activeItem;
1589 this.fireEvent("mouseout", this, e, t);
1594 * Displays this menu relative to another element
1595 * @param {String/HTMLElement/Roo.Element} element The element to align to
1596 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1597 * the element (defaults to this.defaultAlign)
1598 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1600 show : function(el, pos, parentMenu){
1601 this.parentMenu = parentMenu;
1605 this.fireEvent("beforeshow", this);
1606 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1609 * Displays this menu at a specific xy position
1610 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1611 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1613 showAt : function(xy, parentMenu, /* private: */_e){
1614 this.parentMenu = parentMenu;
1619 this.fireEvent("beforeshow", this);
1621 //xy = this.el.adjustForConstraints(xy);
1623 //this.el.setXY(xy);
1625 this.hideMenuItems();
1626 this.hidden = false;
1627 this.triggerEl.addClass('open');
1629 this.fireEvent("show", this);
1635 this.doFocus.defer(50, this);
1639 doFocus : function(){
1641 this.focusEl.focus();
1646 * Hides this menu and optionally all parent menus
1647 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1649 hide : function(deep){
1651 this.hideMenuItems();
1652 if(this.el && this.isVisible()){
1653 this.fireEvent("beforehide", this);
1654 if(this.activeItem){
1655 this.activeItem.deactivate();
1656 this.activeItem = null;
1658 this.triggerEl.removeClass('open');;
1660 this.fireEvent("hide", this);
1662 if(deep === true && this.parentMenu){
1663 this.parentMenu.hide(true);
1667 onTriggerPress : function(e)
1670 Roo.log('trigger press');
1671 //Roo.log(e.getTarget());
1672 // Roo.log(this.triggerEl.dom);
1673 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1676 if (this.isVisible()) {
1680 this.show(this.triggerEl, false, false);
1689 hideMenuItems : function()
1691 //$(backdrop).remove()
1692 Roo.select('.open',true).each(function(aa) {
1694 aa.removeClass('open');
1695 //var parent = getParent($(this))
1696 //var relatedTarget = { relatedTarget: this }
1698 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1699 //if (e.isDefaultPrevented()) return
1700 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1703 addxtypeChild : function (tree, cntr) {
1704 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1706 this.menuitems.add(comp);
1727 * @class Roo.bootstrap.MenuItem
1728 * @extends Roo.bootstrap.Component
1729 * Bootstrap MenuItem class
1730 * @cfg {String} html the menu label
1731 * @cfg {String} href the link
1732 * @cfg {Boolean} preventDefault (true | false) default true
1736 * Create a new MenuItem
1737 * @param {Object} config The config object
1741 Roo.bootstrap.MenuItem = function(config){
1742 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1747 * The raw click event for the entire grid.
1748 * @param {Roo.EventObject} e
1754 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1758 preventDefault: true,
1760 getAutoCreate : function(){
1763 cls: 'dropdown-menu-item',
1772 if (this.parent().type == 'treeview') {
1773 cfg.cls = 'treeview-menu';
1776 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1777 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1781 initEvents: function() {
1783 //this.el.select('a').on('click', this.onClick, this);
1786 onClick : function(e)
1788 Roo.log('item on click ');
1789 //if(this.preventDefault){
1790 // e.preventDefault();
1792 //this.parent().hideMenuItems();
1794 this.fireEvent('click', this, e);
1813 * @class Roo.bootstrap.MenuSeparator
1814 * @extends Roo.bootstrap.Component
1815 * Bootstrap MenuSeparator class
1818 * Create a new MenuItem
1819 * @param {Object} config The config object
1823 Roo.bootstrap.MenuSeparator = function(config){
1824 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1827 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1829 getAutoCreate : function(){
1844 <div class="modal fade">
1845 <div class="modal-dialog">
1846 <div class="modal-content">
1847 <div class="modal-header">
1848 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1849 <h4 class="modal-title">Modal title</h4>
1851 <div class="modal-body">
1852 <p>One fine body…</p>
1854 <div class="modal-footer">
1855 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1856 <button type="button" class="btn btn-primary">Save changes</button>
1858 </div><!-- /.modal-content -->
1859 </div><!-- /.modal-dialog -->
1860 </div><!-- /.modal -->
1870 * @class Roo.bootstrap.Modal
1871 * @extends Roo.bootstrap.Component
1872 * Bootstrap Modal class
1873 * @cfg {String} title Title of dialog
1874 * @cfg {Boolean} specificTitle (true|false) default false
1875 * @cfg {Array} buttons Array of buttons or standard button set..
1876 * @cfg {String} buttonPosition (left|right|center) default right
1879 * Create a new Modal Dialog
1880 * @param {Object} config The config object
1883 Roo.bootstrap.Modal = function(config){
1884 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1889 * The raw btnclick event for the button
1890 * @param {Roo.EventObject} e
1894 this.buttons = this.buttons || [];
1897 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1899 title : 'test dialog',
1906 specificTitle: false,
1908 buttonPosition: 'right',
1910 onRender : function(ct, position)
1912 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1915 var cfg = Roo.apply({}, this.getAutoCreate());
1918 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1920 //if (!cfg.name.length) {
1924 cfg.cls += ' ' + this.cls;
1927 cfg.style = this.style;
1929 this.el = Roo.get(document.body).createChild(cfg, position);
1931 //var type = this.el.dom.type;
1933 if(this.tabIndex !== undefined){
1934 this.el.dom.setAttribute('tabIndex', this.tabIndex);
1939 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1940 this.maskEl.enableDisplayMode("block");
1942 //this.el.addClass("x-dlg-modal");
1944 if (this.buttons.length) {
1945 Roo.each(this.buttons, function(bb) {
1946 b = Roo.apply({}, bb);
1947 b.xns = b.xns || Roo.bootstrap;
1948 b.xtype = b.xtype || 'Button';
1949 if (typeof(b.listeners) == 'undefined') {
1950 b.listeners = { click : this.onButtonClick.createDelegate(this) };
1953 var btn = Roo.factory(b);
1955 btn.onRender(this.el.select('.modal-footer div').first());
1959 // render the children.
1962 if(typeof(this.items) != 'undefined'){
1963 var items = this.items;
1966 for(var i =0;i < items.length;i++) {
1967 nitems.push(this.addxtype(Roo.apply({}, items[i])));
1971 this.items = nitems;
1973 this.body = this.el.select('.modal-body',true).first();
1974 this.close = this.el.select('.modal-header .close', true).first();
1975 this.footer = this.el.select('.modal-footer',true).first();
1977 //this.el.addClass([this.fieldClass, this.cls]);
1980 getAutoCreate : function(){
1985 html : this.html || ''
1990 cls : 'modal-title',
1994 if(this.specificTitle){
2000 style : 'display: none',
2003 cls: "modal-dialog",
2006 cls : "modal-content",
2009 cls : 'modal-header',
2021 cls : 'modal-footer',
2025 cls: 'btn-' + this.buttonPosition
2044 getChildContainer : function() {
2046 return this.el.select('.modal-body',true).first();
2049 getButtonContainer : function() {
2050 return this.el.select('.modal-footer div',true).first();
2053 initEvents : function()
2055 this.el.select('.modal-header .close').on('click', this.hide, this);
2057 // this.addxtype(this);
2061 if (!this.rendered) {
2065 this.el.addClass('on');
2066 this.el.removeClass('fade');
2067 this.el.setStyle('display', 'block');
2068 Roo.get(document.body).addClass("x-body-masked");
2069 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2071 this.el.setStyle('zIndex', '10001');
2072 this.fireEvent('show', this);
2078 Roo.log('Modal hide?!');
2080 Roo.get(document.body).removeClass("x-body-masked");
2081 this.el.removeClass('on');
2082 this.el.addClass('fade');
2083 this.el.setStyle('display', 'none');
2084 this.fireEvent('hide', this);
2087 addButton : function(str, cb)
2091 var b = Roo.apply({}, { html : str } );
2092 b.xns = b.xns || Roo.bootstrap;
2093 b.xtype = b.xtype || 'Button';
2094 if (typeof(b.listeners) == 'undefined') {
2095 b.listeners = { click : cb.createDelegate(this) };
2098 var btn = Roo.factory(b);
2100 btn.onRender(this.el.select('.modal-footer div').first());
2106 setDefaultButton : function(btn)
2108 //this.el.select('.modal-footer').()
2110 resizeTo: function(w,h)
2114 setContentSize : function(w, h)
2118 onButtonClick: function(btn,e)
2121 this.fireEvent('btnclick', btn.name, e);
2123 setTitle: function(str) {
2124 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2130 Roo.apply(Roo.bootstrap.Modal, {
2132 * Button config that displays a single OK button
2141 * Button config that displays Yes and No buttons
2157 * Button config that displays OK and Cancel buttons
2172 * Button config that displays Yes, No and Cancel buttons
2194 * messagebox - can be used as a replace
2198 * @class Roo.MessageBox
2199 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2203 Roo.Msg.alert('Status', 'Changes saved successfully.');
2205 // Prompt for user data:
2206 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2208 // process text value...
2212 // Show a dialog using config options:
2214 title:'Save Changes?',
2215 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2216 buttons: Roo.Msg.YESNOCANCEL,
2223 Roo.bootstrap.MessageBox = function(){
2224 var dlg, opt, mask, waitTimer;
2225 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2226 var buttons, activeTextEl, bwidth;
2230 var handleButton = function(button){
2232 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2236 var handleHide = function(){
2238 dlg.el.removeClass(opt.cls);
2241 // Roo.TaskMgr.stop(waitTimer);
2242 // waitTimer = null;
2247 var updateButtons = function(b){
2250 buttons["ok"].hide();
2251 buttons["cancel"].hide();
2252 buttons["yes"].hide();
2253 buttons["no"].hide();
2254 //dlg.footer.dom.style.display = 'none';
2257 dlg.footer.dom.style.display = '';
2258 for(var k in buttons){
2259 if(typeof buttons[k] != "function"){
2262 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2263 width += buttons[k].el.getWidth()+15;
2273 var handleEsc = function(d, k, e){
2274 if(opt && opt.closable !== false){
2284 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2285 * @return {Roo.BasicDialog} The BasicDialog element
2287 getDialog : function(){
2289 dlg = new Roo.bootstrap.Modal( {
2292 //constraintoviewport:false,
2294 //collapsible : false,
2299 //buttonAlign:"center",
2300 closeClick : function(){
2301 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2304 handleButton("cancel");
2309 dlg.on("hide", handleHide);
2311 //dlg.addKeyListener(27, handleEsc);
2313 this.buttons = buttons;
2314 var bt = this.buttonText;
2315 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2316 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2317 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2318 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2320 bodyEl = dlg.body.createChild({
2322 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2323 '<textarea class="roo-mb-textarea"></textarea>' +
2324 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2326 msgEl = bodyEl.dom.firstChild;
2327 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2328 textboxEl.enableDisplayMode();
2329 textboxEl.addKeyListener([10,13], function(){
2330 if(dlg.isVisible() && opt && opt.buttons){
2333 }else if(opt.buttons.yes){
2334 handleButton("yes");
2338 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2339 textareaEl.enableDisplayMode();
2340 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2341 progressEl.enableDisplayMode();
2342 var pf = progressEl.dom.firstChild;
2344 pp = Roo.get(pf.firstChild);
2345 pp.setHeight(pf.offsetHeight);
2353 * Updates the message box body text
2354 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2355 * the XHTML-compliant non-breaking space character '&#160;')
2356 * @return {Roo.MessageBox} This message box
2358 updateText : function(text){
2359 if(!dlg.isVisible() && !opt.width){
2360 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2362 msgEl.innerHTML = text || ' ';
2364 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2365 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2367 Math.min(opt.width || cw , this.maxWidth),
2368 Math.max(opt.minWidth || this.minWidth, bwidth)
2371 activeTextEl.setWidth(w);
2373 if(dlg.isVisible()){
2374 dlg.fixedcenter = false;
2376 // to big, make it scroll. = But as usual stupid IE does not support
2379 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2380 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2381 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2383 bodyEl.dom.style.height = '';
2384 bodyEl.dom.style.overflowY = '';
2387 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2389 bodyEl.dom.style.overflowX = '';
2392 dlg.setContentSize(w, bodyEl.getHeight());
2393 if(dlg.isVisible()){
2394 dlg.fixedcenter = true;
2400 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2401 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2402 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2403 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2404 * @return {Roo.MessageBox} This message box
2406 updateProgress : function(value, text){
2408 this.updateText(text);
2410 if (pp) { // weird bug on my firefox - for some reason this is not defined
2411 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2417 * Returns true if the message box is currently displayed
2418 * @return {Boolean} True if the message box is visible, else false
2420 isVisible : function(){
2421 return dlg && dlg.isVisible();
2425 * Hides the message box if it is displayed
2428 if(this.isVisible()){
2434 * Displays a new message box, or reinitializes an existing message box, based on the config options
2435 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2436 * The following config object properties are supported:
2438 Property Type Description
2439 ---------- --------------- ------------------------------------------------------------------------------------
2440 animEl String/Element An id or Element from which the message box should animate as it opens and
2441 closes (defaults to undefined)
2442 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2443 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2444 closable Boolean False to hide the top-right close button (defaults to true). Note that
2445 progress and wait dialogs will ignore this property and always hide the
2446 close button as they can only be closed programmatically.
2447 cls String A custom CSS class to apply to the message box element
2448 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2449 displayed (defaults to 75)
2450 fn Function A callback function to execute after closing the dialog. The arguments to the
2451 function will be btn (the name of the button that was clicked, if applicable,
2452 e.g. "ok"), and text (the value of the active text field, if applicable).
2453 Progress and wait dialogs will ignore this option since they do not respond to
2454 user actions and can only be closed programmatically, so any required function
2455 should be called by the same code after it closes the dialog.
2456 icon String A CSS class that provides a background image to be used as an icon for
2457 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2458 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2459 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2460 modal Boolean False to allow user interaction with the page while the message box is
2461 displayed (defaults to true)
2462 msg String A string that will replace the existing message box body text (defaults
2463 to the XHTML-compliant non-breaking space character ' ')
2464 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2465 progress Boolean True to display a progress bar (defaults to false)
2466 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2467 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2468 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2469 title String The title text
2470 value String The string value to set into the active textbox element if displayed
2471 wait Boolean True to display a progress bar (defaults to false)
2472 width Number The width of the dialog in pixels
2479 msg: 'Please enter your address:',
2481 buttons: Roo.MessageBox.OKCANCEL,
2484 animEl: 'addAddressBtn'
2487 * @param {Object} config Configuration options
2488 * @return {Roo.MessageBox} This message box
2490 show : function(options)
2493 // this causes nightmares if you show one dialog after another
2494 // especially on callbacks..
2496 if(this.isVisible()){
2499 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2500 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2501 Roo.log("New Dialog Message:" + options.msg )
2502 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2503 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2506 var d = this.getDialog();
2508 d.setTitle(opt.title || " ");
2509 d.close.setDisplayed(opt.closable !== false);
2510 activeTextEl = textboxEl;
2511 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2516 textareaEl.setHeight(typeof opt.multiline == "number" ?
2517 opt.multiline : this.defaultTextHeight);
2518 activeTextEl = textareaEl;
2527 progressEl.setDisplayed(opt.progress === true);
2528 this.updateProgress(0);
2529 activeTextEl.dom.value = opt.value || "";
2531 dlg.setDefaultButton(activeTextEl);
2533 var bs = opt.buttons;
2537 }else if(bs && bs.yes){
2538 db = buttons["yes"];
2540 dlg.setDefaultButton(db);
2542 bwidth = updateButtons(opt.buttons);
2543 this.updateText(opt.msg);
2545 d.el.addClass(opt.cls);
2547 d.proxyDrag = opt.proxyDrag === true;
2548 d.modal = opt.modal !== false;
2549 d.mask = opt.modal !== false ? mask : false;
2551 // force it to the end of the z-index stack so it gets a cursor in FF
2552 document.body.appendChild(dlg.el.dom);
2553 d.animateTarget = null;
2554 d.show(options.animEl);
2560 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2561 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2562 * and closing the message box when the process is complete.
2563 * @param {String} title The title bar text
2564 * @param {String} msg The message box body text
2565 * @return {Roo.MessageBox} This message box
2567 progress : function(title, msg){
2574 minWidth: this.minProgressWidth,
2581 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2582 * If a callback function is passed it will be called after the user clicks the button, and the
2583 * id of the button that was clicked will be passed as the only parameter to the callback
2584 * (could also be the top-right close button).
2585 * @param {String} title The title bar text
2586 * @param {String} msg The message box body text
2587 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2588 * @param {Object} scope (optional) The scope of the callback function
2589 * @return {Roo.MessageBox} This message box
2591 alert : function(title, msg, fn, scope){
2604 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2605 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2606 * You are responsible for closing the message box when the process is complete.
2607 * @param {String} msg The message box body text
2608 * @param {String} title (optional) The title bar text
2609 * @return {Roo.MessageBox} This message box
2611 wait : function(msg, title){
2622 waitTimer = Roo.TaskMgr.start({
2624 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2632 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2633 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2634 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2635 * @param {String} title The title bar text
2636 * @param {String} msg The message box body text
2637 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2638 * @param {Object} scope (optional) The scope of the callback function
2639 * @return {Roo.MessageBox} This message box
2641 confirm : function(title, msg, fn, scope){
2645 buttons: this.YESNO,
2654 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2655 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2656 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2657 * (could also be the top-right close button) and the text that was entered will be passed as the two
2658 * parameters to the callback.
2659 * @param {String} title The title bar text
2660 * @param {String} msg The message box body text
2661 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2662 * @param {Object} scope (optional) The scope of the callback function
2663 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2664 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2665 * @return {Roo.MessageBox} This message box
2667 prompt : function(title, msg, fn, scope, multiline){
2671 buttons: this.OKCANCEL,
2676 multiline: multiline,
2683 * Button config that displays a single OK button
2688 * Button config that displays Yes and No buttons
2691 YESNO : {yes:true, no:true},
2693 * Button config that displays OK and Cancel buttons
2696 OKCANCEL : {ok:true, cancel:true},
2698 * Button config that displays Yes, No and Cancel buttons
2701 YESNOCANCEL : {yes:true, no:true, cancel:true},
2704 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2707 defaultTextHeight : 75,
2709 * The maximum width in pixels of the message box (defaults to 600)
2714 * The minimum width in pixels of the message box (defaults to 100)
2719 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2720 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2723 minProgressWidth : 250,
2725 * An object containing the default button text strings that can be overriden for localized language support.
2726 * Supported properties are: ok, cancel, yes and no.
2727 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2740 * Shorthand for {@link Roo.MessageBox}
2742 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2743 Roo.Msg = Roo.Msg || Roo.MessageBox;
2752 * @class Roo.bootstrap.Navbar
2753 * @extends Roo.bootstrap.Component
2754 * Bootstrap Navbar class
2757 * Create a new Navbar
2758 * @param {Object} config The config object
2762 Roo.bootstrap.Navbar = function(config){
2763 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2767 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2776 getAutoCreate : function(){
2779 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
2783 initEvents :function ()
2785 //Roo.log(this.el.select('.navbar-toggle',true));
2786 this.el.select('.navbar-toggle',true).on('click', function() {
2787 // Roo.log('click');
2788 this.el.select('.navbar-collapse',true).toggleClass('in');
2796 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2798 var size = this.el.getSize();
2799 this.maskEl.setSize(size.width, size.height);
2800 this.maskEl.enableDisplayMode("block");
2809 getChildContainer : function()
2811 if (this.el.select('.collapse').getCount()) {
2812 return this.el.select('.collapse',true).first();
2845 * @class Roo.bootstrap.NavSimplebar
2846 * @extends Roo.bootstrap.Navbar
2847 * Bootstrap Sidebar class
2849 * @cfg {Boolean} inverse is inverted color
2851 * @cfg {String} type (nav | pills | tabs)
2852 * @cfg {Boolean} arrangement stacked | justified
2853 * @cfg {String} align (left | right) alignment
2855 * @cfg {Boolean} main (true|false) main nav bar? default false
2856 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
2858 * @cfg {String} tag (header|footer|nav|div) default is nav
2864 * Create a new Sidebar
2865 * @param {Object} config The config object
2869 Roo.bootstrap.NavSimplebar = function(config){
2870 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
2873 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
2889 getAutoCreate : function(){
2893 tag : this.tag || 'div',
2906 this.type = this.type || 'nav';
2907 if (['tabs','pills'].indexOf(this.type)!==-1) {
2908 cfg.cn[0].cls += ' nav-' + this.type
2912 if (this.type!=='nav') {
2913 Roo.log('nav type must be nav/tabs/pills')
2915 cfg.cn[0].cls += ' navbar-nav'
2921 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
2922 cfg.cn[0].cls += ' nav-' + this.arrangement;
2926 if (this.align === 'right') {
2927 cfg.cn[0].cls += ' navbar-right';
2931 cfg.cls += ' navbar-inverse';
2958 * @class Roo.bootstrap.NavHeaderbar
2959 * @extends Roo.bootstrap.NavSimplebar
2960 * Bootstrap Sidebar class
2962 * @cfg {String} brand what is brand
2963 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
2964 * @cfg {String} brand_href href of the brand
2967 * Create a new Sidebar
2968 * @param {Object} config The config object
2972 Roo.bootstrap.NavHeaderbar = function(config){
2973 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
2976 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
2983 getAutoCreate : function(){
2988 tag: this.nav || 'nav',
2994 cls: 'navbar-header',
2999 cls: 'navbar-toggle',
3000 'data-toggle': 'collapse',
3005 html: 'Toggle navigation'
3025 cls: 'collapse navbar-collapse'
3030 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3032 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3033 cfg.cls += ' navbar-' + this.position;
3035 // tag can override this..
3037 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3040 if (this.brand !== '') {
3043 href: this.brand_href ? this.brand_href : '#',
3044 cls: 'navbar-brand',
3052 cfg.cls += ' main-nav';
3077 * @class Roo.bootstrap.NavSidebar
3078 * @extends Roo.bootstrap.Navbar
3079 * Bootstrap Sidebar class
3082 * Create a new Sidebar
3083 * @param {Object} config The config object
3087 Roo.bootstrap.NavSidebar = function(config){
3088 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3091 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3093 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3095 getAutoCreate : function(){
3100 cls: 'sidebar sidebar-nav'
3122 * @class Roo.bootstrap.NavGroup
3123 * @extends Roo.bootstrap.Component
3124 * Bootstrap NavGroup class
3125 * @cfg {String} align left | right
3126 * @cfg {Boolean} inverse false | true
3127 * @cfg {String} type (nav|pills|tab) default nav
3128 * @cfg {String} navId - reference Id for navbar.
3132 * Create a new nav group
3133 * @param {Object} config The config object
3136 Roo.bootstrap.NavGroup = function(config){
3137 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3139 Roo.bootstrap.NavGroup.register(this);
3143 * Fires when the active item changes
3144 * @param {Roo.bootstrap.NavGroup} this
3145 * @param {Roo.bootstrap.Navbar.Item} item The item selected
3146 * @param {Roo.bootstrap.Navbar.Item} item The previously selected item
3153 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3164 getAutoCreate : function()
3166 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3173 if (['tabs','pills'].indexOf(this.type)!==-1) {
3174 cfg.cls += ' nav-' + this.type
3176 if (this.type!=='nav') {
3177 Roo.log('nav type must be nav/tabs/pills')
3179 cfg.cls += ' navbar-nav'
3182 if (this.parent().sidebar) {
3185 cls: 'dashboard-menu sidebar-menu'
3191 if (this.form === true) {
3197 if (this.align === 'right') {
3198 cfg.cls += ' navbar-right';
3200 cfg.cls += ' navbar-left';
3204 if (this.align === 'right') {
3205 cfg.cls += ' navbar-right';
3209 cfg.cls += ' navbar-inverse';
3217 setActiveItem : function(item)
3220 Roo.each(this.navItems, function(v){
3225 v.setActive(false, true);
3232 item.setActive(true, true);
3233 this.fireEvent('changed', this, item, prev);
3238 addItem : function(cfg)
3240 var cn = new Roo.bootstrap.NavItem(cfg);
3242 cn.parentId = this.id;
3243 cn.onRender(this.el, null);
3247 register : function(item)
3249 this.navItems.push( item);
3250 item.navId = this.navId;
3253 getNavItem: function(tabId)
3256 Roo.each(this.navItems, function(e) {
3257 if (e.tabId == tabId) {
3273 Roo.apply(Roo.bootstrap.NavGroup, {
3277 register : function(navgrp)
3279 this.groups[navgrp.navId] = navgrp;
3282 get: function(navId) {
3283 return this.groups[navId];
3298 * @class Roo.bootstrap.NavItem
3299 * @extends Roo.bootstrap.Component
3300 * Bootstrap Navbar.NavItem class
3301 * @cfg {String} href link to
3302 * @cfg {String} html content of button
3303 * @cfg {String} badge text inside badge
3304 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3305 * @cfg {String} glyphicon name of glyphicon
3306 * @cfg {String} icon name of font awesome icon
3307 * @cfg {Boolean} active Is item active
3308 * @cfg {Boolean} disabled Is item disabled
3310 * @cfg {Boolean} preventDefault (true | false) default false
3311 * @cfg {String} tabId the tab that this item activates.
3312 * @cfg {String} tagtype (a|span) render as a href or span?
3315 * Create a new Navbar Item
3316 * @param {Object} config The config object
3318 Roo.bootstrap.NavItem = function(config){
3319 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3324 * The raw click event for the entire grid.
3325 * @param {Roo.EventObject} e
3330 * Fires when the active item active state changes
3331 * @param {Roo.bootstrap.NavItem} this
3332 * @param {boolean} state the new state
3340 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3348 preventDefault : false,
3353 getAutoCreate : function(){
3361 href : this.href || "#",
3362 html: this.html || ''
3368 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3371 // glyphicon and icon go before content..
3372 if (this.glyphicon || this.icon) {
3374 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3376 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3384 cfg.cn[0].html += " <span class='caret'></span>";
3388 if (this.badge !== '') {
3390 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3392 if (this.disabled) {
3393 cfg.cls += ' disabled';
3399 initEvents: function() {
3400 // Roo.log('init events?');
3401 // Roo.log(this.el.dom);
3402 if (typeof (this.menu) != 'undefined') {
3403 this.menu.parentType = this.xtype;
3404 this.menu.triggerEl = this.el;
3405 this.addxtype(Roo.apply({}, this.menu));
3409 this.el.select('a',true).on('click', this.onClick, this);
3410 // at this point parent should be available..
3411 this.parent().register(this);
3414 onClick : function(e)
3417 if(this.preventDefault){
3420 if (this.disabled) {
3423 Roo.log("fire event clicked");
3424 if(this.fireEvent('click', this, e) === false){
3428 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3429 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3430 this.parent().setActiveItem(this);
3438 isActive: function () {
3441 setActive : function(state, fire)
3443 this.active = state;
3445 this.el.removeClass('active');
3446 } else if (!this.el.hasClass('active')) {
3447 this.el.addClass('active');
3450 this.fireEvent('changed', this, state);
3455 // this should not be here...
3456 setDisabled : function(state)
3458 this.disabled = state;
3460 this.el.removeClass('disabled');
3461 } else if (!this.el.hasClass('disabled')) {
3462 this.el.addClass('disabled');
3475 * <span> icon </span>
3476 * <span> text </span>
3477 * <span>badge </span>
3481 * @class Roo.bootstrap.NavSidebarItem
3482 * @extends Roo.bootstrap.NavItem
3483 * Bootstrap Navbar.NavSidebarItem class
3485 * Create a new Navbar Button
3486 * @param {Object} config The config object
3488 Roo.bootstrap.NavSidebarItem = function(config){
3489 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3494 * The raw click event for the entire grid.
3495 * @param {Roo.EventObject} e
3500 * Fires when the active item active state changes
3501 * @param {Roo.bootstrap.NavSidebarItem} this
3502 * @param {boolean} state the new state
3510 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3513 getAutoCreate : function(){
3518 href : this.href || '#',
3530 html : this.html || ''
3535 cfg.cls += ' active';
3539 if (this.glyphicon || this.icon) {
3540 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3541 a.cn.push({ tag : 'i', cls : c }) ;
3546 if (this.badge !== '') {
3547 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3551 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3552 a.cls += 'dropdown-toggle treeview' ;
3576 * @class Roo.bootstrap.Row
3577 * @extends Roo.bootstrap.Component
3578 * Bootstrap Row class (contains columns...)
3582 * @param {Object} config The config object
3585 Roo.bootstrap.Row = function(config){
3586 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3589 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3591 getAutoCreate : function(){
3610 * @class Roo.bootstrap.Element
3611 * @extends Roo.bootstrap.Component
3612 * Bootstrap Element class
3613 * @cfg {String} html contents of the element
3614 * @cfg {String} tag tag of the element
3615 * @cfg {String} cls class of the element
3618 * Create a new Element
3619 * @param {Object} config The config object
3622 Roo.bootstrap.Element = function(config){
3623 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3626 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3633 getAutoCreate : function(){
3658 * @class Roo.bootstrap.Pagination
3659 * @extends Roo.bootstrap.Component
3660 * Bootstrap Pagination class
3661 * @cfg {String} size xs | sm | md | lg
3662 * @cfg {Boolean} inverse false | true
3665 * Create a new Pagination
3666 * @param {Object} config The config object
3669 Roo.bootstrap.Pagination = function(config){
3670 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3673 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3679 getAutoCreate : function(){
3685 cfg.cls += ' inverse';
3691 cfg.cls += " " + this.cls;
3709 * @class Roo.bootstrap.PaginationItem
3710 * @extends Roo.bootstrap.Component
3711 * Bootstrap PaginationItem class
3712 * @cfg {String} html text
3713 * @cfg {String} href the link
3714 * @cfg {Boolean} preventDefault (true | false) default true
3715 * @cfg {Boolean} active (true | false) default false
3719 * Create a new PaginationItem
3720 * @param {Object} config The config object
3724 Roo.bootstrap.PaginationItem = function(config){
3725 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3730 * The raw click event for the entire grid.
3731 * @param {Roo.EventObject} e
3737 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
3741 preventDefault: true,
3745 getAutoCreate : function(){
3751 href : this.href ? this.href : '#',
3752 html : this.html ? this.html : ''
3762 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
3768 initEvents: function() {
3770 this.el.on('click', this.onClick, this);
3773 onClick : function(e)
3775 Roo.log('PaginationItem on click ');
3776 if(this.preventDefault){
3780 this.fireEvent('click', this, e);
3796 * @class Roo.bootstrap.Slider
3797 * @extends Roo.bootstrap.Component
3798 * Bootstrap Slider class
3801 * Create a new Slider
3802 * @param {Object} config The config object
3805 Roo.bootstrap.Slider = function(config){
3806 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
3809 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
3811 getAutoCreate : function(){
3815 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
3819 cls: 'ui-slider-handle ui-state-default ui-corner-all'
3837 * @class Roo.bootstrap.Table
3838 * @extends Roo.bootstrap.Component
3839 * Bootstrap Table class
3840 * @cfg {String} cls table class
3841 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
3842 * @cfg {String} bgcolor Specifies the background color for a table
3843 * @cfg {Number} border Specifies whether the table cells should have borders or not
3844 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
3845 * @cfg {Number} cellspacing Specifies the space between cells
3846 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
3847 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
3848 * @cfg {String} sortable Specifies that the table should be sortable
3849 * @cfg {String} summary Specifies a summary of the content of a table
3850 * @cfg {Number} width Specifies the width of a table
3852 * @cfg {boolean} striped Should the rows be alternative striped
3853 * @cfg {boolean} bordered Add borders to the table
3854 * @cfg {boolean} hover Add hover highlighting
3855 * @cfg {boolean} condensed Format condensed
3856 * @cfg {boolean} responsive Format condensed
3857 * @cfg {Boolean} loadMask (true|false) default false
3859 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
3863 * Create a new Table
3864 * @param {Object} config The config object
3867 Roo.bootstrap.Table = function(config){
3868 Roo.bootstrap.Table.superclass.constructor.call(this, config);
3871 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
3872 this.sm = this.selModel;
3873 this.sm.xmodule = this.xmodule || false;
3875 if (this.cm && typeof(this.cm.config) == 'undefined') {
3876 this.colModel = Roo.factory(this.cm, Roo.grid);
3877 this.cm = this.colModel;
3878 this.cm.xmodule = this.xmodule || false;
3881 this.store= Roo.factory(this.store, Roo.data);
3882 this.ds = this.store;
3883 this.ds.xmodule = this.xmodule || false;
3886 if (this.footer && this.store) {
3887 this.footer.dataSource = this.ds;
3888 this.footer = Roo.factory(this.footer);
3892 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
3915 getAutoCreate : function(){
3916 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
3925 cfg.cls += ' table-striped';
3928 cfg.cls += ' table-hover';
3930 if (this.bordered) {
3931 cfg.cls += ' table-bordered';
3933 if (this.condensed) {
3934 cfg.cls += ' table-condensed';
3936 if (this.responsive) {
3937 cfg.cls += ' table-responsive';
3944 cfg.cls+= ' ' +this.cls;
3947 // this lot should be simplifed...
3950 cfg.align=this.align;
3953 cfg.bgcolor=this.bgcolor;
3956 cfg.border=this.border;
3958 if (this.cellpadding) {
3959 cfg.cellpadding=this.cellpadding;
3961 if (this.cellspacing) {
3962 cfg.cellspacing=this.cellspacing;
3965 cfg.frame=this.frame;
3968 cfg.rules=this.rules;
3970 if (this.sortable) {
3971 cfg.sortable=this.sortable;
3974 cfg.summary=this.summary;
3977 cfg.width=this.width;
3980 if(this.store || this.cm){
3981 cfg.cn.push(this.renderHeader());
3982 cfg.cn.push(this.renderBody());
3983 cfg.cn.push(this.renderFooter());
3985 cfg.cls+= ' TableGrid';
3991 // initTableGrid : function()
4000 // var cm = this.cm;
4002 // for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4005 // html: cm.getColumnHeader(i)
4009 // cfg.push(header);
4016 initEvents : function()
4018 if(!this.store || !this.cm){
4022 Roo.log('initEvents with ds!!!!');
4026 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4027 e.on('click', _this.sort, _this);
4029 // this.maskEl = Roo.DomHelper.append(this.el.select('.TableGrid', true).first(), {tag: "div", cls:"x-dlg-mask"}, true);
4030 // this.maskEl.enableDisplayMode("block");
4031 // this.maskEl.show();
4033 this.parent().el.setStyle('position', 'relative');
4035 this.footer.parentId = this.id;
4036 this.footer.onRender(this.el.select('tfoot tr td'), null);
4040 // mask should be using Roo.bootstrap.Mask...
4045 style: "text-align:center",
4049 style: "background-color:white;width:50%;margin:100 auto",
4053 src: rootURL + '/roojs1/images/ux/lightbox/loading.gif'
4064 this.maskEl = Roo.DomHelper.append(this.parent().el, mark, true);
4066 var size = this.parent().el.getSize();
4068 this.maskEl.setSize(size.width, 300); // we will fix the height at the beginning...
4070 this.maskEl.enableDisplayMode("block");
4072 this.store.on('load', this.onLoad, this);
4073 this.store.on('beforeload', this.onBeforeLoad, this);
4081 sort : function(e,el)
4083 var col = Roo.get(el)
4085 if(!col.hasClass('sortable')){
4089 var sort = col.attr('sort');
4092 if(col.hasClass('glyphicon-arrow-up')){
4096 this.store.sortInfo = {field : sort, direction : dir};
4101 renderHeader : function()
4110 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4112 var config = cm.config[i];
4114 if(typeof(config.hidden) != 'undefined' && config.hidden){
4120 html: cm.getColumnHeader(i)
4123 if(typeof(config.dataIndex) != 'undefined'){
4124 c.sort = config.dataIndex;
4127 if(typeof(config.sortable) != 'undefined' && config.sortable){
4131 if(typeof(config.width) != 'undefined'){
4132 c.style = 'width:' + config.width + 'px';
4141 renderBody : function()
4151 renderFooter : function()
4173 Roo.log('ds onload');
4178 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4179 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
4181 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
4182 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
4185 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
4186 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
4190 var tbody = this.el.select('tbody', true).first();
4194 if(this.store.getCount() > 0){
4195 this.store.data.each(function(d){
4201 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4202 var config = cm.config[i];
4204 if(typeof(config.hidden) != 'undefined' && config.hidden){
4208 var renderer = cm.getRenderer(i);
4212 if(typeof(renderer) !== 'undefined'){
4213 value = renderer(d.data[cm.getDataIndex(i)], false, d);
4216 if(typeof(value) === 'object'){
4226 html: (typeof(value) === 'object') ? '' : value
4229 if(typeof(config.width) != 'undefined'){
4230 td.style = 'width:' + config.width + 'px';
4237 tbody.createChild(row);
4245 Roo.each(renders, function(r){
4246 _this.renderColumn(r);
4255 onBeforeLoad : function()
4257 Roo.log('ds onBeforeLoad');
4268 this.el.select('tbody', true).first().dom.innerHTML = '';
4271 getSelectionModel : function(){
4273 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
4275 return this.selModel;
4278 renderColumn : function(r)
4281 r.cfg.render(Roo.get(r.id));
4284 Roo.each(r.cfg.cn, function(c){
4289 _this.renderColumn(child);
4306 * @class Roo.bootstrap.TableCell
4307 * @extends Roo.bootstrap.Component
4308 * Bootstrap TableCell class
4309 * @cfg {String} html cell contain text
4310 * @cfg {String} cls cell class
4311 * @cfg {String} tag cell tag (td|th) default td
4312 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
4313 * @cfg {String} align Aligns the content in a cell
4314 * @cfg {String} axis Categorizes cells
4315 * @cfg {String} bgcolor Specifies the background color of a cell
4316 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
4317 * @cfg {Number} colspan Specifies the number of columns a cell should span
4318 * @cfg {String} headers Specifies one or more header cells a cell is related to
4319 * @cfg {Number} height Sets the height of a cell
4320 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
4321 * @cfg {Number} rowspan Sets the number of rows a cell should span
4322 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
4323 * @cfg {String} valign Vertical aligns the content in a cell
4324 * @cfg {Number} width Specifies the width of a cell
4327 * Create a new TableCell
4328 * @param {Object} config The config object
4331 Roo.bootstrap.TableCell = function(config){
4332 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
4335 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
4355 getAutoCreate : function(){
4356 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
4376 cfg.align=this.align
4382 cfg.bgcolor=this.bgcolor
4385 cfg.charoff=this.charoff
4388 cfg.colspan=this.colspan
4391 cfg.headers=this.headers
4394 cfg.height=this.height
4397 cfg.nowrap=this.nowrap
4400 cfg.rowspan=this.rowspan
4403 cfg.scope=this.scope
4406 cfg.valign=this.valign
4409 cfg.width=this.width
4428 * @class Roo.bootstrap.TableRow
4429 * @extends Roo.bootstrap.Component
4430 * Bootstrap TableRow class
4431 * @cfg {String} cls row class
4432 * @cfg {String} align Aligns the content in a table row
4433 * @cfg {String} bgcolor Specifies a background color for a table row
4434 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
4435 * @cfg {String} valign Vertical aligns the content in a table row
4438 * Create a new TableRow
4439 * @param {Object} config The config object
4442 Roo.bootstrap.TableRow = function(config){
4443 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
4446 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
4454 getAutoCreate : function(){
4455 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
4465 cfg.align = this.align;
4468 cfg.bgcolor = this.bgcolor;
4471 cfg.charoff = this.charoff;
4474 cfg.valign = this.valign;
4492 * @class Roo.bootstrap.TableBody
4493 * @extends Roo.bootstrap.Component
4494 * Bootstrap TableBody class
4495 * @cfg {String} cls element class
4496 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
4497 * @cfg {String} align Aligns the content inside the element
4498 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
4499 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
4502 * Create a new TableBody
4503 * @param {Object} config The config object
4506 Roo.bootstrap.TableBody = function(config){
4507 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
4510 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
4518 getAutoCreate : function(){
4519 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
4533 cfg.align = this.align;
4536 cfg.charoff = this.charoff;
4539 cfg.valign = this.valign;
4546 // initEvents : function()
4553 // this.store = Roo.factory(this.store, Roo.data);
4554 // this.store.on('load', this.onLoad, this);
4556 // this.store.load();
4560 // onLoad: function ()
4562 // this.fireEvent('load', this);
4572 * Ext JS Library 1.1.1
4573 * Copyright(c) 2006-2007, Ext JS, LLC.
4575 * Originally Released Under LGPL - original licence link has changed is not relivant.
4578 * <script type="text/javascript">
4581 // as we use this in bootstrap.
4582 Roo.namespace('Roo.form');
4584 * @class Roo.form.Action
4585 * Internal Class used to handle form actions
4587 * @param {Roo.form.BasicForm} el The form element or its id
4588 * @param {Object} config Configuration options
4593 // define the action interface
4594 Roo.form.Action = function(form, options){
4596 this.options = options || {};
4599 * Client Validation Failed
4602 Roo.form.Action.CLIENT_INVALID = 'client';
4604 * Server Validation Failed
4607 Roo.form.Action.SERVER_INVALID = 'server';
4609 * Connect to Server Failed
4612 Roo.form.Action.CONNECT_FAILURE = 'connect';
4614 * Reading Data from Server Failed
4617 Roo.form.Action.LOAD_FAILURE = 'load';
4619 Roo.form.Action.prototype = {
4621 failureType : undefined,
4622 response : undefined,
4626 run : function(options){
4631 success : function(response){
4636 handleResponse : function(response){
4640 // default connection failure
4641 failure : function(response){
4643 this.response = response;
4644 this.failureType = Roo.form.Action.CONNECT_FAILURE;
4645 this.form.afterAction(this, false);
4648 processResponse : function(response){
4649 this.response = response;
4650 if(!response.responseText){
4653 this.result = this.handleResponse(response);
4657 // utility functions used internally
4658 getUrl : function(appendParams){
4659 var url = this.options.url || this.form.url || this.form.el.dom.action;
4661 var p = this.getParams();
4663 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
4669 getMethod : function(){
4670 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
4673 getParams : function(){
4674 var bp = this.form.baseParams;
4675 var p = this.options.params;
4677 if(typeof p == "object"){
4678 p = Roo.urlEncode(Roo.applyIf(p, bp));
4679 }else if(typeof p == 'string' && bp){
4680 p += '&' + Roo.urlEncode(bp);
4683 p = Roo.urlEncode(bp);
4688 createCallback : function(){
4690 success: this.success,
4691 failure: this.failure,
4693 timeout: (this.form.timeout*1000),
4694 upload: this.form.fileUpload ? this.success : undefined
4699 Roo.form.Action.Submit = function(form, options){
4700 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
4703 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
4706 haveProgress : false,
4707 uploadComplete : false,
4709 // uploadProgress indicator.
4710 uploadProgress : function()
4712 if (!this.form.progressUrl) {
4716 if (!this.haveProgress) {
4717 Roo.MessageBox.progress("Uploading", "Uploading");
4719 if (this.uploadComplete) {
4720 Roo.MessageBox.hide();
4724 this.haveProgress = true;
4726 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
4728 var c = new Roo.data.Connection();
4730 url : this.form.progressUrl,
4735 success : function(req){
4736 //console.log(data);
4740 rdata = Roo.decode(req.responseText)
4742 Roo.log("Invalid data from server..");
4746 if (!rdata || !rdata.success) {
4748 Roo.MessageBox.alert(Roo.encode(rdata));
4751 var data = rdata.data;
4753 if (this.uploadComplete) {
4754 Roo.MessageBox.hide();
4759 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
4760 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
4763 this.uploadProgress.defer(2000,this);
4766 failure: function(data) {
4767 Roo.log('progress url failed ');
4778 // run get Values on the form, so it syncs any secondary forms.
4779 this.form.getValues();
4781 var o = this.options;
4782 var method = this.getMethod();
4783 var isPost = method == 'POST';
4784 if(o.clientValidation === false || this.form.isValid()){
4786 if (this.form.progressUrl) {
4787 this.form.findField('UPLOAD_IDENTIFIER').setValue(
4788 (new Date() * 1) + '' + Math.random());
4793 Roo.Ajax.request(Roo.apply(this.createCallback(), {
4794 form:this.form.el.dom,
4795 url:this.getUrl(!isPost),
4797 params:isPost ? this.getParams() : null,
4798 isUpload: this.form.fileUpload
4801 this.uploadProgress();
4803 }else if (o.clientValidation !== false){ // client validation failed
4804 this.failureType = Roo.form.Action.CLIENT_INVALID;
4805 this.form.afterAction(this, false);
4809 success : function(response)
4811 this.uploadComplete= true;
4812 if (this.haveProgress) {
4813 Roo.MessageBox.hide();
4817 var result = this.processResponse(response);
4818 if(result === true || result.success){
4819 this.form.afterAction(this, true);
4823 this.form.markInvalid(result.errors);
4824 this.failureType = Roo.form.Action.SERVER_INVALID;
4826 this.form.afterAction(this, false);
4828 failure : function(response)
4830 this.uploadComplete= true;
4831 if (this.haveProgress) {
4832 Roo.MessageBox.hide();
4835 this.response = response;
4836 this.failureType = Roo.form.Action.CONNECT_FAILURE;
4837 this.form.afterAction(this, false);
4840 handleResponse : function(response){
4841 if(this.form.errorReader){
4842 var rs = this.form.errorReader.read(response);
4845 for(var i = 0, len = rs.records.length; i < len; i++) {
4846 var r = rs.records[i];
4850 if(errors.length < 1){
4854 success : rs.success,
4860 ret = Roo.decode(response.responseText);
4864 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
4874 Roo.form.Action.Load = function(form, options){
4875 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
4876 this.reader = this.form.reader;
4879 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
4884 Roo.Ajax.request(Roo.apply(
4885 this.createCallback(), {
4886 method:this.getMethod(),
4887 url:this.getUrl(false),
4888 params:this.getParams()
4892 success : function(response){
4894 var result = this.processResponse(response);
4895 if(result === true || !result.success || !result.data){
4896 this.failureType = Roo.form.Action.LOAD_FAILURE;
4897 this.form.afterAction(this, false);
4900 this.form.clearInvalid();
4901 this.form.setValues(result.data);
4902 this.form.afterAction(this, true);
4905 handleResponse : function(response){
4906 if(this.form.reader){
4907 var rs = this.form.reader.read(response);
4908 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
4910 success : rs.success,
4914 return Roo.decode(response.responseText);
4918 Roo.form.Action.ACTION_TYPES = {
4919 'load' : Roo.form.Action.Load,
4920 'submit' : Roo.form.Action.Submit
4929 * @class Roo.bootstrap.Form
4930 * @extends Roo.bootstrap.Component
4931 * Bootstrap Form class
4932 * @cfg {String} method GET | POST (default POST)
4933 * @cfg {String} labelAlign top | left (default top)
4934 * @cfg {String} align left | right - for navbars
4939 * @param {Object} config The config object
4943 Roo.bootstrap.Form = function(config){
4944 Roo.bootstrap.Form.superclass.constructor.call(this, config);
4947 * @event clientvalidation
4948 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
4949 * @param {Form} this
4950 * @param {Boolean} valid true if the form has passed client-side validation
4952 clientvalidation: true,
4954 * @event beforeaction
4955 * Fires before any action is performed. Return false to cancel the action.
4956 * @param {Form} this
4957 * @param {Action} action The action to be performed
4961 * @event actionfailed
4962 * Fires when an action fails.
4963 * @param {Form} this
4964 * @param {Action} action The action that failed
4966 actionfailed : true,
4968 * @event actioncomplete
4969 * Fires when an action is completed.
4970 * @param {Form} this
4971 * @param {Action} action The action that completed
4973 actioncomplete : true
4978 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
4981 * @cfg {String} method
4982 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
4987 * The URL to use for form actions if one isn't supplied in the action options.
4990 * @cfg {Boolean} fileUpload
4991 * Set to true if this form is a file upload.
4995 * @cfg {Object} baseParams
4996 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
5000 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
5004 * @cfg {Sting} align (left|right) for navbar forms
5009 activeAction : null,
5012 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5013 * element by passing it or its id or mask the form itself by passing in true.
5016 waitMsgTarget : false,
5021 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5022 * element by passing it or its id or mask the form itself by passing in true.
5026 getAutoCreate : function(){
5030 method : this.method || 'POST',
5031 id : this.id || Roo.id(),
5034 if (this.parent().xtype.match(/^Nav/)) {
5035 cfg.cls = 'navbar-form navbar-' + this.align;
5039 if (this.labelAlign == 'left' ) {
5040 cfg.cls += ' form-horizontal';
5046 initEvents : function()
5048 this.el.on('submit', this.onSubmit, this);
5053 onSubmit : function(e){
5058 * Returns true if client-side validation on the form is successful.
5061 isValid : function(){
5062 var items = this.getItems();
5064 items.each(function(f){
5073 * Returns true if any fields in this form have changed since their original load.
5076 isDirty : function(){
5078 var items = this.getItems();
5079 items.each(function(f){
5089 * Performs a predefined action (submit or load) or custom actions you define on this form.
5090 * @param {String} actionName The name of the action type
5091 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
5092 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
5093 * accept other config options):
5095 Property Type Description
5096 ---------------- --------------- ----------------------------------------------------------------------------------
5097 url String The url for the action (defaults to the form's url)
5098 method String The form method to use (defaults to the form's method, or POST if not defined)
5099 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
5100 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
5101 validate the form on the client (defaults to false)
5103 * @return {BasicForm} this
5105 doAction : function(action, options){
5106 if(typeof action == 'string'){
5107 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
5109 if(this.fireEvent('beforeaction', this, action) !== false){
5110 this.beforeAction(action);
5111 action.run.defer(100, action);
5117 beforeAction : function(action){
5118 var o = action.options;
5120 // not really supported yet.. ??
5122 //if(this.waitMsgTarget === true){
5123 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
5124 //}else if(this.waitMsgTarget){
5125 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
5126 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
5128 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
5134 afterAction : function(action, success){
5135 this.activeAction = null;
5136 var o = action.options;
5138 //if(this.waitMsgTarget === true){
5140 //}else if(this.waitMsgTarget){
5141 // this.waitMsgTarget.unmask();
5143 // Roo.MessageBox.updateProgress(1);
5144 // Roo.MessageBox.hide();
5151 Roo.callback(o.success, o.scope, [this, action]);
5152 this.fireEvent('actioncomplete', this, action);
5156 // failure condition..
5157 // we have a scenario where updates need confirming.
5158 // eg. if a locking scenario exists..
5159 // we look for { errors : { needs_confirm : true }} in the response.
5161 (typeof(action.result) != 'undefined') &&
5162 (typeof(action.result.errors) != 'undefined') &&
5163 (typeof(action.result.errors.needs_confirm) != 'undefined')
5166 Roo.log("not supported yet");
5169 Roo.MessageBox.confirm(
5170 "Change requires confirmation",
5171 action.result.errorMsg,
5176 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
5186 Roo.callback(o.failure, o.scope, [this, action]);
5187 // show an error message if no failed handler is set..
5188 if (!this.hasListener('actionfailed')) {
5189 Roo.log("need to add dialog support");
5191 Roo.MessageBox.alert("Error",
5192 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
5193 action.result.errorMsg :
5194 "Saving Failed, please check your entries or try again"
5199 this.fireEvent('actionfailed', this, action);
5204 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
5205 * @param {String} id The value to search for
5208 findField : function(id){
5209 var items = this.getItems();
5210 var field = items.get(id);
5212 items.each(function(f){
5213 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
5220 return field || null;
5223 * Mark fields in this form invalid in bulk.
5224 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
5225 * @return {BasicForm} this
5227 markInvalid : function(errors){
5228 if(errors instanceof Array){
5229 for(var i = 0, len = errors.length; i < len; i++){
5230 var fieldError = errors[i];
5231 var f = this.findField(fieldError.id);
5233 f.markInvalid(fieldError.msg);
5239 if(typeof errors[id] != 'function' && (field = this.findField(id))){
5240 field.markInvalid(errors[id]);
5244 //Roo.each(this.childForms || [], function (f) {
5245 // f.markInvalid(errors);
5252 * Set values for fields in this form in bulk.
5253 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
5254 * @return {BasicForm} this
5256 setValues : function(values){
5257 if(values instanceof Array){ // array of objects
5258 for(var i = 0, len = values.length; i < len; i++){
5260 var f = this.findField(v.id);
5262 f.setValue(v.value);
5263 if(this.trackResetOnLoad){
5264 f.originalValue = f.getValue();
5268 }else{ // object hash
5271 if(typeof values[id] != 'function' && (field = this.findField(id))){
5273 if (field.setFromData &&
5275 field.displayField &&
5276 // combos' with local stores can
5277 // be queried via setValue()
5278 // to set their value..
5279 (field.store && !field.store.isLocal)
5283 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
5284 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
5285 field.setFromData(sd);
5288 field.setValue(values[id]);
5292 if(this.trackResetOnLoad){
5293 field.originalValue = field.getValue();
5299 //Roo.each(this.childForms || [], function (f) {
5300 // f.setValues(values);
5307 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
5308 * they are returned as an array.
5309 * @param {Boolean} asString
5312 getValues : function(asString){
5313 //if (this.childForms) {
5314 // copy values from the child forms
5315 // Roo.each(this.childForms, function (f) {
5316 // this.setValues(f.getValues());
5322 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
5323 if(asString === true){
5326 return Roo.urlDecode(fs);
5330 * Returns the fields in this form as an object with key/value pairs.
5331 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
5334 getFieldValues : function(with_hidden)
5336 var items = this.getItems();
5338 items.each(function(f){
5342 var v = f.getValue();
5343 if (f.inputType =='radio') {
5344 if (typeof(ret[f.getName()]) == 'undefined') {
5345 ret[f.getName()] = ''; // empty..
5348 if (!f.el.dom.checked) {
5356 // not sure if this supported any more..
5357 if ((typeof(v) == 'object') && f.getRawValue) {
5358 v = f.getRawValue() ; // dates..
5360 // combo boxes where name != hiddenName...
5361 if (f.name != f.getName()) {
5362 ret[f.name] = f.getRawValue();
5364 ret[f.getName()] = v;
5371 * Clears all invalid messages in this form.
5372 * @return {BasicForm} this
5374 clearInvalid : function(){
5375 var items = this.getItems();
5377 items.each(function(f){
5388 * @return {BasicForm} this
5391 var items = this.getItems();
5392 items.each(function(f){
5396 Roo.each(this.childForms || [], function (f) {
5403 getItems : function()
5405 var r=new Roo.util.MixedCollection(false, function(o){
5406 return o.id || (o.id = Roo.id());
5408 var iter = function(el) {
5415 Roo.each(el.items,function(e) {
5434 * Ext JS Library 1.1.1
5435 * Copyright(c) 2006-2007, Ext JS, LLC.
5437 * Originally Released Under LGPL - original licence link has changed is not relivant.
5440 * <script type="text/javascript">
5443 * @class Roo.form.VTypes
5444 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
5447 Roo.form.VTypes = function(){
5448 // closure these in so they are only created once.
5449 var alpha = /^[a-zA-Z_]+$/;
5450 var alphanum = /^[a-zA-Z0-9_]+$/;
5451 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
5452 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
5454 // All these messages and functions are configurable
5457 * The function used to validate email addresses
5458 * @param {String} value The email address
5460 'email' : function(v){
5461 return email.test(v);
5464 * The error text to display when the email validation function returns false
5467 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
5469 * The keystroke filter mask to be applied on email input
5472 'emailMask' : /[a-z0-9_\.\-@]/i,
5475 * The function used to validate URLs
5476 * @param {String} value The URL
5478 'url' : function(v){
5482 * The error text to display when the url validation function returns false
5485 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
5488 * The function used to validate alpha values
5489 * @param {String} value The value
5491 'alpha' : function(v){
5492 return alpha.test(v);
5495 * The error text to display when the alpha validation function returns false
5498 'alphaText' : 'This field should only contain letters and _',
5500 * The keystroke filter mask to be applied on alpha input
5503 'alphaMask' : /[a-z_]/i,
5506 * The function used to validate alphanumeric values
5507 * @param {String} value The value
5509 'alphanum' : function(v){
5510 return alphanum.test(v);
5513 * The error text to display when the alphanumeric validation function returns false
5516 'alphanumText' : 'This field should only contain letters, numbers and _',
5518 * The keystroke filter mask to be applied on alphanumeric input
5521 'alphanumMask' : /[a-z0-9_]/i
5531 * @class Roo.bootstrap.Input
5532 * @extends Roo.bootstrap.Component
5533 * Bootstrap Input class
5534 * @cfg {Boolean} disabled is it disabled
5535 * @cfg {String} fieldLabel - the label associated
5536 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
5537 * @cfg {String} name name of the input
5538 * @cfg {string} fieldLabel - the label associated
5539 * @cfg {string} inputType - input / file submit ...
5540 * @cfg {string} placeholder - placeholder to put in text.
5541 * @cfg {string} before - input group add on before
5542 * @cfg {string} after - input group add on after
5543 * @cfg {string} size - (lg|sm) or leave empty..
5544 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
5545 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
5546 * @cfg {Number} md colspan out of 12 for computer-sized screens
5547 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
5548 * @cfg {string} value default value of the input
5549 * @cfg {Number} labelWidth set the width of label (0-12)
5550 * @cfg {String} labelAlign (top|left)
5551 * @cfg {Boolean} readOnly Specifies that the field should be read-only
5555 * Create a new Input
5556 * @param {Object} config The config object
5559 Roo.bootstrap.Input = function(config){
5560 Roo.bootstrap.Input.superclass.constructor.call(this, config);
5565 * Fires when this field receives input focus.
5566 * @param {Roo.form.Field} this
5571 * Fires when this field loses input focus.
5572 * @param {Roo.form.Field} this
5577 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
5578 * {@link Roo.EventObject#getKey} to determine which key was pressed.
5579 * @param {Roo.form.Field} this
5580 * @param {Roo.EventObject} e The event object
5585 * Fires just before the field blurs if the field value has changed.
5586 * @param {Roo.form.Field} this
5587 * @param {Mixed} newValue The new value
5588 * @param {Mixed} oldValue The original value
5593 * Fires after the field has been marked as invalid.
5594 * @param {Roo.form.Field} this
5595 * @param {String} msg The validation message
5600 * Fires after the field has been validated with no errors.
5601 * @param {Roo.form.Field} this
5606 * Fires after the key up
5607 * @param {Roo.form.Field} this
5608 * @param {Roo.EventObject} e The event Object
5614 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
5616 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
5617 automatic validation (defaults to "keyup").
5619 validationEvent : "keyup",
5621 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
5623 validateOnBlur : true,
5625 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
5627 validationDelay : 250,
5629 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
5631 focusClass : "x-form-focus", // not needed???
5635 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
5637 invalidClass : "has-error",
5640 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
5642 selectOnFocus : false,
5645 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
5649 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
5654 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
5656 disableKeyFilter : false,
5659 * @cfg {Boolean} disabled True to disable the field (defaults to false).
5663 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
5667 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
5669 blankText : "This field is required",
5672 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
5676 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
5678 maxLength : Number.MAX_VALUE,
5680 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
5682 minLengthText : "The minimum length for this field is {0}",
5684 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
5686 maxLengthText : "The maximum length for this field is {0}",
5690 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
5691 * If available, this function will be called only after the basic validators all return true, and will be passed the
5692 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
5696 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
5697 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
5698 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
5702 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
5725 parentLabelAlign : function()
5728 while (parent.parent()) {
5729 parent = parent.parent();
5730 if (typeof(parent.labelAlign) !='undefined') {
5731 return parent.labelAlign;
5738 getAutoCreate : function(){
5740 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
5746 if(this.inputType != 'hidden'){
5747 cfg.cls = 'form-group' //input-group
5753 type : this.inputType,
5755 cls : 'form-control',
5756 placeholder : this.placeholder || ''
5760 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
5761 input.maxLength = this.maxLength;
5764 if (this.disabled) {
5765 input.disabled=true;
5768 if (this.readOnly) {
5769 input.readonly=true;
5773 input.name = this.name;
5776 input.cls += ' input-' + this.size;
5779 ['xs','sm','md','lg'].map(function(size){
5780 if (settings[size]) {
5781 cfg.cls += ' col-' + size + '-' + settings[size];
5785 var inputblock = input;
5787 if (this.before || this.after) {
5790 cls : 'input-group',
5793 if (this.before && typeof(this.before) == 'string') {
5795 inputblock.cn.push({
5797 cls : 'roo-input-before input-group-addon',
5801 if (this.before && typeof(this.before) == 'object') {
5802 this.before = Roo.factory(this.before);
5803 Roo.log(this.before);
5804 inputblock.cn.push({
5806 cls : 'roo-input-before input-group-' +
5807 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
5811 inputblock.cn.push(input);
5813 if (this.after && typeof(this.after) == 'string') {
5814 inputblock.cn.push({
5816 cls : 'roo-input-after input-group-addon',
5820 if (this.after && typeof(this.after) == 'object') {
5821 this.after = Roo.factory(this.after);
5822 Roo.log(this.after);
5823 inputblock.cn.push({
5825 cls : 'roo-input-after input-group-' +
5826 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
5831 if (align ==='left' && this.fieldLabel.length) {
5832 Roo.log("left and has label");
5838 cls : 'control-label col-sm-' + this.labelWidth,
5839 html : this.fieldLabel
5843 cls : "col-sm-" + (12 - this.labelWidth),
5850 } else if ( this.fieldLabel.length) {
5856 //cls : 'input-group-addon',
5857 html : this.fieldLabel
5867 Roo.log(" no label && no align");
5876 Roo.log('input-parentType: ' + this.parentType);
5878 if (this.parentType === 'Navbar' && this.parent().bar) {
5879 cfg.cls += ' navbar-form';
5887 * return the real input element.
5889 inputEl: function ()
5891 return this.el.select('input.form-control',true).first();
5893 setDisabled : function(v)
5895 var i = this.inputEl().dom;
5897 i.removeAttribute('disabled');
5901 i.setAttribute('disabled','true');
5903 initEvents : function()
5906 this.inputEl().on("keydown" , this.fireKey, this);
5907 this.inputEl().on("focus", this.onFocus, this);
5908 this.inputEl().on("blur", this.onBlur, this);
5910 this.inputEl().relayEvent('keyup', this);
5912 // reference to original value for reset
5913 this.originalValue = this.getValue();
5914 //Roo.form.TextField.superclass.initEvents.call(this);
5915 if(this.validationEvent == 'keyup'){
5916 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
5917 this.inputEl().on('keyup', this.filterValidation, this);
5919 else if(this.validationEvent !== false){
5920 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
5923 if(this.selectOnFocus){
5924 this.on("focus", this.preFocus, this);
5927 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
5928 this.inputEl().on("keypress", this.filterKeys, this);
5931 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
5932 this.el.on("click", this.autoSize, this);
5935 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
5936 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
5939 if (typeof(this.before) == 'object') {
5940 this.before.render(this.el.select('.roo-input-before',true).first());
5942 if (typeof(this.after) == 'object') {
5943 this.after.render(this.el.select('.roo-input-after',true).first());
5948 filterValidation : function(e){
5949 if(!e.isNavKeyPress()){
5950 this.validationTask.delay(this.validationDelay);
5954 * Validates the field value
5955 * @return {Boolean} True if the value is valid, else false
5957 validate : function(){
5958 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
5959 if(this.disabled || this.validateValue(this.getRawValue())){
5960 this.clearInvalid();
5968 * Validates a value according to the field's validation rules and marks the field as invalid
5969 * if the validation fails
5970 * @param {Mixed} value The value to validate
5971 * @return {Boolean} True if the value is valid, else false
5973 validateValue : function(value){
5974 if(value.length < 1) { // if it's blank
5975 if(this.allowBlank){
5976 this.clearInvalid();
5979 this.markInvalid(this.blankText);
5983 if(value.length < this.minLength){
5984 this.markInvalid(String.format(this.minLengthText, this.minLength));
5987 if(value.length > this.maxLength){
5988 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
5992 var vt = Roo.form.VTypes;
5993 if(!vt[this.vtype](value, this)){
5994 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
5998 if(typeof this.validator == "function"){
5999 var msg = this.validator(value);
6001 this.markInvalid(msg);
6005 if(this.regex && !this.regex.test(value)){
6006 this.markInvalid(this.regexText);
6015 fireKey : function(e){
6016 //Roo.log('field ' + e.getKey());
6017 if(e.isNavKeyPress()){
6018 this.fireEvent("specialkey", this, e);
6021 focus : function (selectText){
6023 this.inputEl().focus();
6024 if(selectText === true){
6025 this.inputEl().dom.select();
6031 onFocus : function(){
6032 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6033 // this.el.addClass(this.focusClass);
6036 this.hasFocus = true;
6037 this.startValue = this.getValue();
6038 this.fireEvent("focus", this);
6042 beforeBlur : Roo.emptyFn,
6046 onBlur : function(){
6048 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6049 //this.el.removeClass(this.focusClass);
6051 this.hasFocus = false;
6052 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
6055 var v = this.getValue();
6056 if(String(v) !== String(this.startValue)){
6057 this.fireEvent('change', this, v, this.startValue);
6059 this.fireEvent("blur", this);
6063 * Resets the current field value to the originally loaded value and clears any validation messages
6066 this.setValue(this.originalValue);
6067 this.clearInvalid();
6070 * Returns the name of the field
6071 * @return {Mixed} name The name field
6073 getName: function(){
6077 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
6078 * @return {Mixed} value The field value
6080 getValue : function(){
6081 return this.inputEl().getValue();
6084 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
6085 * @return {Mixed} value The field value
6087 getRawValue : function(){
6088 var v = this.inputEl().getValue();
6094 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
6095 * @param {Mixed} value The value to set
6097 setRawValue : function(v){
6098 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6101 selectText : function(start, end){
6102 var v = this.getRawValue();
6104 start = start === undefined ? 0 : start;
6105 end = end === undefined ? v.length : end;
6106 var d = this.inputEl().dom;
6107 if(d.setSelectionRange){
6108 d.setSelectionRange(start, end);
6109 }else if(d.createTextRange){
6110 var range = d.createTextRange();
6111 range.moveStart("character", start);
6112 range.moveEnd("character", v.length-end);
6119 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
6120 * @param {Mixed} value The value to set
6122 setValue : function(v){
6125 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6131 processValue : function(value){
6132 if(this.stripCharsRe){
6133 var newValue = value.replace(this.stripCharsRe, '');
6134 if(newValue !== value){
6135 this.setRawValue(newValue);
6142 preFocus : function(){
6144 if(this.selectOnFocus){
6145 this.inputEl().dom.select();
6148 filterKeys : function(e){
6150 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
6153 var c = e.getCharCode(), cc = String.fromCharCode(c);
6154 if(Roo.isIE && (e.isSpecialKey() || !cc)){
6157 if(!this.maskRe.test(cc)){
6162 * Clear any invalid styles/messages for this field
6164 clearInvalid : function(){
6166 if(!this.el || this.preventMark){ // not rendered
6169 this.el.removeClass(this.invalidClass);
6171 switch(this.msgTarget){
6173 this.el.dom.qtip = '';
6176 this.el.dom.title = '';
6180 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
6185 this.errorIcon.dom.qtip = '';
6186 this.errorIcon.hide();
6187 this.un('resize', this.alignErrorIcon, this);
6191 var t = Roo.getDom(this.msgTarget);
6193 t.style.display = 'none';
6197 this.fireEvent('valid', this);
6200 * Mark this field as invalid
6201 * @param {String} msg The validation message
6203 markInvalid : function(msg){
6204 if(!this.el || this.preventMark){ // not rendered
6207 this.el.addClass(this.invalidClass);
6209 msg = msg || this.invalidText;
6210 switch(this.msgTarget){
6212 this.el.dom.qtip = msg;
6213 this.el.dom.qclass = 'x-form-invalid-tip';
6214 if(Roo.QuickTips){ // fix for floating editors interacting with DND
6215 Roo.QuickTips.enable();
6219 this.el.dom.title = msg;
6223 var elp = this.el.findParent('.x-form-element', 5, true);
6224 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
6225 this.errorEl.setWidth(elp.getWidth(true)-20);
6227 this.errorEl.update(msg);
6228 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
6231 if(!this.errorIcon){
6232 var elp = this.el.findParent('.x-form-element', 5, true);
6233 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
6235 this.alignErrorIcon();
6236 this.errorIcon.dom.qtip = msg;
6237 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
6238 this.errorIcon.show();
6239 this.on('resize', this.alignErrorIcon, this);
6242 var t = Roo.getDom(this.msgTarget);
6244 t.style.display = this.msgDisplay;
6248 this.fireEvent('invalid', this, msg);
6251 SafariOnKeyDown : function(event)
6253 // this is a workaround for a password hang bug on chrome/ webkit.
6255 var isSelectAll = false;
6257 if(this.inputEl().dom.selectionEnd > 0){
6258 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
6260 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
6261 event.preventDefault();
6266 if(isSelectAll){ // backspace and delete key
6268 event.preventDefault();
6269 // this is very hacky as keydown always get's upper case.
6271 var cc = String.fromCharCode(event.getCharCode());
6272 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
6276 adjustWidth : function(tag, w){
6277 tag = tag.toLowerCase();
6278 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
6279 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
6283 if(tag == 'textarea'){
6286 }else if(Roo.isOpera){
6290 if(tag == 'textarea'){
6309 * @class Roo.bootstrap.TextArea
6310 * @extends Roo.bootstrap.Input
6311 * Bootstrap TextArea class
6312 * @cfg {Number} cols Specifies the visible width of a text area
6313 * @cfg {Number} rows Specifies the visible number of lines in a text area
6314 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
6315 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
6316 * @cfg {string} html text
6319 * Create a new TextArea
6320 * @param {Object} config The config object
6323 Roo.bootstrap.TextArea = function(config){
6324 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
6328 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
6338 getAutoCreate : function(){
6340 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6351 value : this.value || '',
6352 html: this.html || '',
6353 cls : 'form-control',
6354 placeholder : this.placeholder || ''
6358 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6359 input.maxLength = this.maxLength;
6363 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
6367 input.cols = this.cols;
6370 if (this.readOnly) {
6371 input.readonly = true;
6375 input.name = this.name;
6379 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
6383 ['xs','sm','md','lg'].map(function(size){
6384 if (settings[size]) {
6385 cfg.cls += ' col-' + size + '-' + settings[size];
6389 var inputblock = input;
6391 if (this.before || this.after) {
6394 cls : 'input-group',
6398 inputblock.cn.push({
6400 cls : 'input-group-addon',
6404 inputblock.cn.push(input);
6406 inputblock.cn.push({
6408 cls : 'input-group-addon',
6415 if (align ==='left' && this.fieldLabel.length) {
6416 Roo.log("left and has label");
6422 cls : 'control-label col-sm-' + this.labelWidth,
6423 html : this.fieldLabel
6427 cls : "col-sm-" + (12 - this.labelWidth),
6434 } else if ( this.fieldLabel.length) {
6440 //cls : 'input-group-addon',
6441 html : this.fieldLabel
6451 Roo.log(" no label && no align");
6461 if (this.disabled) {
6462 input.disabled=true;
6469 * return the real textarea element.
6471 inputEl: function ()
6473 return this.el.select('textarea.form-control',true).first();
6481 * trigger field - base class for combo..
6486 * @class Roo.bootstrap.TriggerField
6487 * @extends Roo.bootstrap.Input
6488 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
6489 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
6490 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
6491 * for which you can provide a custom implementation. For example:
6493 var trigger = new Roo.bootstrap.TriggerField();
6494 trigger.onTriggerClick = myTriggerFn;
6495 trigger.applyTo('my-field');
6498 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
6499 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
6500 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
6501 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
6503 * Create a new TriggerField.
6504 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
6505 * to the base TextField)
6507 Roo.bootstrap.TriggerField = function(config){
6508 this.mimicing = false;
6509 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
6512 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
6514 * @cfg {String} triggerClass A CSS class to apply to the trigger
6517 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
6521 /** @cfg {Boolean} grow @hide */
6522 /** @cfg {Number} growMin @hide */
6523 /** @cfg {Number} growMax @hide */
6529 autoSize: Roo.emptyFn,
6536 actionMode : 'wrap',
6540 getAutoCreate : function(){
6542 var parent = this.parent();
6544 var align = this.labelAlign || this.parentLabelAlign();
6549 cls: 'form-group' //input-group
6556 type : this.inputType,
6557 cls : 'form-control',
6558 autocomplete: 'off',
6559 placeholder : this.placeholder || ''
6563 input.name = this.name;
6566 input.cls += ' input-' + this.size;
6569 if (this.disabled) {
6570 input.disabled=true;
6573 var inputblock = input;
6575 if (this.before || this.after) {
6578 cls : 'input-group',
6582 inputblock.cn.push({
6584 cls : 'input-group-addon',
6588 inputblock.cn.push(input);
6590 inputblock.cn.push({
6592 cls : 'input-group-addon',
6605 cls: 'form-hidden-field'
6613 Roo.log('multiple');
6621 cls: 'form-hidden-field'
6625 cls: 'select2-choices',
6629 cls: 'select2-search-field',
6642 cls: 'select2-container input-group',
6647 cls: 'typeahead typeahead-long dropdown-menu',
6648 style: 'display:none'
6656 cls : 'input-group-addon btn dropdown-toggle',
6664 cls: 'combobox-clear',
6678 combobox.cls += ' select2-container-multi';
6681 if (align ==='left' && this.fieldLabel.length) {
6683 Roo.log("left and has label");
6689 cls : 'control-label col-sm-' + this.labelWidth,
6690 html : this.fieldLabel
6694 cls : "col-sm-" + (12 - this.labelWidth),
6701 } else if ( this.fieldLabel.length) {
6707 //cls : 'input-group-addon',
6708 html : this.fieldLabel
6718 Roo.log(" no label && no align");
6725 ['xs','sm','md','lg'].map(function(size){
6726 if (settings[size]) {
6727 cfg.cls += ' col-' + size + '-' + settings[size];
6738 onResize : function(w, h){
6739 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
6740 // if(typeof w == 'number'){
6741 // var x = w - this.trigger.getWidth();
6742 // this.inputEl().setWidth(this.adjustWidth('input', x));
6743 // this.trigger.setStyle('left', x+'px');
6748 adjustSize : Roo.BoxComponent.prototype.adjustSize,
6751 getResizeEl : function(){
6752 return this.inputEl();
6756 getPositionEl : function(){
6757 return this.inputEl();
6761 alignErrorIcon : function(){
6762 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
6766 initEvents : function(){
6768 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
6769 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
6771 this.trigger = this.el.select('span.dropdown-toggle',true).first();
6772 if(this.hideTrigger){
6773 this.trigger.setDisplayed(false);
6775 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
6779 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
6782 //this.trigger.addClassOnOver('x-form-trigger-over');
6783 //this.trigger.addClassOnClick('x-form-trigger-click');
6786 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
6791 initTrigger : function(){
6796 onDestroy : function(){
6798 this.trigger.removeAllListeners();
6799 // this.trigger.remove();
6802 // this.wrap.remove();
6804 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
6808 onFocus : function(){
6809 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
6812 this.wrap.addClass('x-trigger-wrap-focus');
6813 this.mimicing = true;
6814 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
6815 if(this.monitorTab){
6816 this.el.on("keydown", this.checkTab, this);
6823 checkTab : function(e){
6824 if(e.getKey() == e.TAB){
6830 onBlur : function(){
6835 mimicBlur : function(e, t){
6837 if(!this.wrap.contains(t) && this.validateBlur()){
6844 triggerBlur : function(){
6845 this.mimicing = false;
6846 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
6847 if(this.monitorTab){
6848 this.el.un("keydown", this.checkTab, this);
6850 //this.wrap.removeClass('x-trigger-wrap-focus');
6851 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
6855 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
6856 validateBlur : function(e, t){
6861 onDisable : function(){
6862 this.inputEl().dom.disabled = true;
6863 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
6865 // this.wrap.addClass('x-item-disabled');
6870 onEnable : function(){
6871 this.inputEl().dom.disabled = false;
6872 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
6874 // this.el.removeClass('x-item-disabled');
6879 onShow : function(){
6880 var ae = this.getActionEl();
6883 ae.dom.style.display = '';
6884 ae.dom.style.visibility = 'visible';
6890 onHide : function(){
6891 var ae = this.getActionEl();
6892 ae.dom.style.display = 'none';
6896 * The function that should handle the trigger's click event. This method does nothing by default until overridden
6897 * by an implementing function.
6899 * @param {EventObject} e
6901 onTriggerClick : Roo.emptyFn
6905 * Ext JS Library 1.1.1
6906 * Copyright(c) 2006-2007, Ext JS, LLC.
6908 * Originally Released Under LGPL - original licence link has changed is not relivant.
6911 * <script type="text/javascript">
6916 * @class Roo.data.SortTypes
6918 * Defines the default sorting (casting?) comparison functions used when sorting data.
6920 Roo.data.SortTypes = {
6922 * Default sort that does nothing
6923 * @param {Mixed} s The value being converted
6924 * @return {Mixed} The comparison value
6931 * The regular expression used to strip tags
6935 stripTagsRE : /<\/?[^>]+>/gi,
6938 * Strips all HTML tags to sort on text only
6939 * @param {Mixed} s The value being converted
6940 * @return {String} The comparison value
6942 asText : function(s){
6943 return String(s).replace(this.stripTagsRE, "");
6947 * Strips all HTML tags to sort on text only - Case insensitive
6948 * @param {Mixed} s The value being converted
6949 * @return {String} The comparison value
6951 asUCText : function(s){
6952 return String(s).toUpperCase().replace(this.stripTagsRE, "");
6956 * Case insensitive string
6957 * @param {Mixed} s The value being converted
6958 * @return {String} The comparison value
6960 asUCString : function(s) {
6961 return String(s).toUpperCase();
6966 * @param {Mixed} s The value being converted
6967 * @return {Number} The comparison value
6969 asDate : function(s) {
6973 if(s instanceof Date){
6976 return Date.parse(String(s));
6981 * @param {Mixed} s The value being converted
6982 * @return {Float} The comparison value
6984 asFloat : function(s) {
6985 var val = parseFloat(String(s).replace(/,/g, ""));
6986 if(isNaN(val)) val = 0;
6992 * @param {Mixed} s The value being converted
6993 * @return {Number} The comparison value
6995 asInt : function(s) {
6996 var val = parseInt(String(s).replace(/,/g, ""));
6997 if(isNaN(val)) val = 0;
7002 * Ext JS Library 1.1.1
7003 * Copyright(c) 2006-2007, Ext JS, LLC.
7005 * Originally Released Under LGPL - original licence link has changed is not relivant.
7008 * <script type="text/javascript">
7012 * @class Roo.data.Record
7013 * Instances of this class encapsulate both record <em>definition</em> information, and record
7014 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
7015 * to access Records cached in an {@link Roo.data.Store} object.<br>
7017 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
7018 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
7021 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
7023 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
7024 * {@link #create}. The parameters are the same.
7025 * @param {Array} data An associative Array of data values keyed by the field name.
7026 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
7027 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
7028 * not specified an integer id is generated.
7030 Roo.data.Record = function(data, id){
7031 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
7036 * Generate a constructor for a specific record layout.
7037 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
7038 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
7039 * Each field definition object may contain the following properties: <ul>
7040 * <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,
7041 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
7042 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
7043 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
7044 * is being used, then this is a string containing the javascript expression to reference the data relative to
7045 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
7046 * to the data item relative to the record element. If the mapping expression is the same as the field name,
7047 * this may be omitted.</p></li>
7048 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
7049 * <ul><li>auto (Default, implies no conversion)</li>
7054 * <li>date</li></ul></p></li>
7055 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
7056 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
7057 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
7058 * by the Reader into an object that will be stored in the Record. It is passed the
7059 * following parameters:<ul>
7060 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
7062 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
7064 * <br>usage:<br><pre><code>
7065 var TopicRecord = Roo.data.Record.create(
7066 {name: 'title', mapping: 'topic_title'},
7067 {name: 'author', mapping: 'username'},
7068 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
7069 {name: 'lastPost', mapping: 'post_time', type: 'date'},
7070 {name: 'lastPoster', mapping: 'user2'},
7071 {name: 'excerpt', mapping: 'post_text'}
7074 var myNewRecord = new TopicRecord({
7075 title: 'Do my job please',
7078 lastPost: new Date(),
7079 lastPoster: 'Animal',
7080 excerpt: 'No way dude!'
7082 myStore.add(myNewRecord);
7087 Roo.data.Record.create = function(o){
7089 f.superclass.constructor.apply(this, arguments);
7091 Roo.extend(f, Roo.data.Record);
7092 var p = f.prototype;
7093 p.fields = new Roo.util.MixedCollection(false, function(field){
7096 for(var i = 0, len = o.length; i < len; i++){
7097 p.fields.add(new Roo.data.Field(o[i]));
7099 f.getField = function(name){
7100 return p.fields.get(name);
7105 Roo.data.Record.AUTO_ID = 1000;
7106 Roo.data.Record.EDIT = 'edit';
7107 Roo.data.Record.REJECT = 'reject';
7108 Roo.data.Record.COMMIT = 'commit';
7110 Roo.data.Record.prototype = {
7112 * Readonly flag - true if this record has been modified.
7121 join : function(store){
7126 * Set the named field to the specified value.
7127 * @param {String} name The name of the field to set.
7128 * @param {Object} value The value to set the field to.
7130 set : function(name, value){
7131 if(this.data[name] == value){
7138 if(typeof this.modified[name] == 'undefined'){
7139 this.modified[name] = this.data[name];
7141 this.data[name] = value;
7142 if(!this.editing && this.store){
7143 this.store.afterEdit(this);
7148 * Get the value of the named field.
7149 * @param {String} name The name of the field to get the value of.
7150 * @return {Object} The value of the field.
7152 get : function(name){
7153 return this.data[name];
7157 beginEdit : function(){
7158 this.editing = true;
7163 cancelEdit : function(){
7164 this.editing = false;
7165 delete this.modified;
7169 endEdit : function(){
7170 this.editing = false;
7171 if(this.dirty && this.store){
7172 this.store.afterEdit(this);
7177 * Usually called by the {@link Roo.data.Store} which owns the Record.
7178 * Rejects all changes made to the Record since either creation, or the last commit operation.
7179 * Modified fields are reverted to their original values.
7181 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
7182 * of reject operations.
7184 reject : function(){
7185 var m = this.modified;
7187 if(typeof m[n] != "function"){
7188 this.data[n] = m[n];
7192 delete this.modified;
7193 this.editing = false;
7195 this.store.afterReject(this);
7200 * Usually called by the {@link Roo.data.Store} which owns the Record.
7201 * Commits all changes made to the Record since either creation, or the last commit operation.
7203 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
7204 * of commit operations.
7206 commit : function(){
7208 delete this.modified;
7209 this.editing = false;
7211 this.store.afterCommit(this);
7216 hasError : function(){
7217 return this.error != null;
7221 clearError : function(){
7226 * Creates a copy of this record.
7227 * @param {String} id (optional) A new record id if you don't want to use this record's id
7230 copy : function(newId) {
7231 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
7235 * Ext JS Library 1.1.1
7236 * Copyright(c) 2006-2007, Ext JS, LLC.
7238 * Originally Released Under LGPL - original licence link has changed is not relivant.
7241 * <script type="text/javascript">
7247 * @class Roo.data.Store
7248 * @extends Roo.util.Observable
7249 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
7250 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
7252 * 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
7253 * has no knowledge of the format of the data returned by the Proxy.<br>
7255 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
7256 * instances from the data object. These records are cached and made available through accessor functions.
7258 * Creates a new Store.
7259 * @param {Object} config A config object containing the objects needed for the Store to access data,
7260 * and read the data into Records.
7262 Roo.data.Store = function(config){
7263 this.data = new Roo.util.MixedCollection(false);
7264 this.data.getKey = function(o){
7267 this.baseParams = {};
7274 "multisort" : "_multisort"
7277 if(config && config.data){
7278 this.inlineData = config.data;
7282 Roo.apply(this, config);
7284 if(this.reader){ // reader passed
7285 this.reader = Roo.factory(this.reader, Roo.data);
7286 this.reader.xmodule = this.xmodule || false;
7287 if(!this.recordType){
7288 this.recordType = this.reader.recordType;
7290 if(this.reader.onMetaChange){
7291 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
7295 if(this.recordType){
7296 this.fields = this.recordType.prototype.fields;
7302 * @event datachanged
7303 * Fires when the data cache has changed, and a widget which is using this Store
7304 * as a Record cache should refresh its view.
7305 * @param {Store} this
7310 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
7311 * @param {Store} this
7312 * @param {Object} meta The JSON metadata
7317 * Fires when Records have been added to the Store
7318 * @param {Store} this
7319 * @param {Roo.data.Record[]} records The array of Records added
7320 * @param {Number} index The index at which the record(s) were added
7325 * Fires when a Record has been removed from the Store
7326 * @param {Store} this
7327 * @param {Roo.data.Record} record The Record that was removed
7328 * @param {Number} index The index at which the record was removed
7333 * Fires when a Record has been updated
7334 * @param {Store} this
7335 * @param {Roo.data.Record} record The Record that was updated
7336 * @param {String} operation The update operation being performed. Value may be one of:
7338 Roo.data.Record.EDIT
7339 Roo.data.Record.REJECT
7340 Roo.data.Record.COMMIT
7346 * Fires when the data cache has been cleared.
7347 * @param {Store} this
7352 * Fires before a request is made for a new data object. If the beforeload handler returns false
7353 * the load action will be canceled.
7354 * @param {Store} this
7355 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7359 * @event beforeloadadd
7360 * Fires after a new set of Records has been loaded.
7361 * @param {Store} this
7362 * @param {Roo.data.Record[]} records The Records that were loaded
7363 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7365 beforeloadadd : true,
7368 * Fires after a new set of Records has been loaded, before they are added to the store.
7369 * @param {Store} this
7370 * @param {Roo.data.Record[]} records The Records that were loaded
7371 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7372 * @params {Object} return from reader
7376 * @event loadexception
7377 * Fires if an exception occurs in the Proxy during loading.
7378 * Called with the signature of the Proxy's "loadexception" event.
7379 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
7382 * @param {Object} return from JsonData.reader() - success, totalRecords, records
7383 * @param {Object} load options
7384 * @param {Object} jsonData from your request (normally this contains the Exception)
7386 loadexception : true
7390 this.proxy = Roo.factory(this.proxy, Roo.data);
7391 this.proxy.xmodule = this.xmodule || false;
7392 this.relayEvents(this.proxy, ["loadexception"]);
7394 this.sortToggle = {};
7395 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
7397 Roo.data.Store.superclass.constructor.call(this);
7399 if(this.inlineData){
7400 this.loadData(this.inlineData);
7401 delete this.inlineData;
7405 Roo.extend(Roo.data.Store, Roo.util.Observable, {
7407 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
7408 * without a remote query - used by combo/forms at present.
7412 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
7415 * @cfg {Array} data Inline data to be loaded when the store is initialized.
7418 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
7419 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
7422 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
7423 * on any HTTP request
7426 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
7429 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
7433 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
7434 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
7439 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
7440 * loaded or when a record is removed. (defaults to false).
7442 pruneModifiedRecords : false,
7448 * Add Records to the Store and fires the add event.
7449 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
7451 add : function(records){
7452 records = [].concat(records);
7453 for(var i = 0, len = records.length; i < len; i++){
7454 records[i].join(this);
7456 var index = this.data.length;
7457 this.data.addAll(records);
7458 this.fireEvent("add", this, records, index);
7462 * Remove a Record from the Store and fires the remove event.
7463 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
7465 remove : function(record){
7466 var index = this.data.indexOf(record);
7467 this.data.removeAt(index);
7468 if(this.pruneModifiedRecords){
7469 this.modified.remove(record);
7471 this.fireEvent("remove", this, record, index);
7475 * Remove all Records from the Store and fires the clear event.
7477 removeAll : function(){
7479 if(this.pruneModifiedRecords){
7482 this.fireEvent("clear", this);
7486 * Inserts Records to the Store at the given index and fires the add event.
7487 * @param {Number} index The start index at which to insert the passed Records.
7488 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
7490 insert : function(index, records){
7491 records = [].concat(records);
7492 for(var i = 0, len = records.length; i < len; i++){
7493 this.data.insert(index, records[i]);
7494 records[i].join(this);
7496 this.fireEvent("add", this, records, index);
7500 * Get the index within the cache of the passed Record.
7501 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
7502 * @return {Number} The index of the passed Record. Returns -1 if not found.
7504 indexOf : function(record){
7505 return this.data.indexOf(record);
7509 * Get the index within the cache of the Record with the passed id.
7510 * @param {String} id The id of the Record to find.
7511 * @return {Number} The index of the Record. Returns -1 if not found.
7513 indexOfId : function(id){
7514 return this.data.indexOfKey(id);
7518 * Get the Record with the specified id.
7519 * @param {String} id The id of the Record to find.
7520 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
7522 getById : function(id){
7523 return this.data.key(id);
7527 * Get the Record at the specified index.
7528 * @param {Number} index The index of the Record to find.
7529 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
7531 getAt : function(index){
7532 return this.data.itemAt(index);
7536 * Returns a range of Records between specified indices.
7537 * @param {Number} startIndex (optional) The starting index (defaults to 0)
7538 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
7539 * @return {Roo.data.Record[]} An array of Records
7541 getRange : function(start, end){
7542 return this.data.getRange(start, end);
7546 storeOptions : function(o){
7547 o = Roo.apply({}, o);
7550 this.lastOptions = o;
7554 * Loads the Record cache from the configured Proxy using the configured Reader.
7556 * If using remote paging, then the first load call must specify the <em>start</em>
7557 * and <em>limit</em> properties in the options.params property to establish the initial
7558 * position within the dataset, and the number of Records to cache on each read from the Proxy.
7560 * <strong>It is important to note that for remote data sources, loading is asynchronous,
7561 * and this call will return before the new data has been loaded. Perform any post-processing
7562 * in a callback function, or in a "load" event handler.</strong>
7564 * @param {Object} options An object containing properties which control loading options:<ul>
7565 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
7566 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
7567 * passed the following arguments:<ul>
7568 * <li>r : Roo.data.Record[]</li>
7569 * <li>options: Options object from the load call</li>
7570 * <li>success: Boolean success indicator</li></ul></li>
7571 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
7572 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
7575 load : function(options){
7576 options = options || {};
7577 if(this.fireEvent("beforeload", this, options) !== false){
7578 this.storeOptions(options);
7579 var p = Roo.apply(options.params || {}, this.baseParams);
7580 // if meta was not loaded from remote source.. try requesting it.
7581 if (!this.reader.metaFromRemote) {
7584 if(this.sortInfo && this.remoteSort){
7585 var pn = this.paramNames;
7586 p[pn["sort"]] = this.sortInfo.field;
7587 p[pn["dir"]] = this.sortInfo.direction;
7589 if (this.multiSort) {
7590 var pn = this.paramNames;
7591 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
7594 this.proxy.load(p, this.reader, this.loadRecords, this, options);
7599 * Reloads the Record cache from the configured Proxy using the configured Reader and
7600 * the options from the last load operation performed.
7601 * @param {Object} options (optional) An object containing properties which may override the options
7602 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
7603 * the most recently used options are reused).
7605 reload : function(options){
7606 this.load(Roo.applyIf(options||{}, this.lastOptions));
7610 // Called as a callback by the Reader during a load operation.
7611 loadRecords : function(o, options, success){
7612 if(!o || success === false){
7613 if(success !== false){
7614 this.fireEvent("load", this, [], options, o);
7616 if(options.callback){
7617 options.callback.call(options.scope || this, [], options, false);
7621 // if data returned failure - throw an exception.
7622 if (o.success === false) {
7623 // show a message if no listener is registered.
7624 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
7625 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
7627 // loadmask wil be hooked into this..
7628 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
7631 var r = o.records, t = o.totalRecords || r.length;
7633 this.fireEvent("beforeloadadd", this, r, options, o);
7635 if(!options || options.add !== true){
7636 if(this.pruneModifiedRecords){
7639 for(var i = 0, len = r.length; i < len; i++){
7643 this.data = this.snapshot;
7644 delete this.snapshot;
7647 this.data.addAll(r);
7648 this.totalLength = t;
7650 this.fireEvent("datachanged", this);
7652 this.totalLength = Math.max(t, this.data.length+r.length);
7655 this.fireEvent("load", this, r, options, o);
7656 if(options.callback){
7657 options.callback.call(options.scope || this, r, options, true);
7663 * Loads data from a passed data block. A Reader which understands the format of the data
7664 * must have been configured in the constructor.
7665 * @param {Object} data The data block from which to read the Records. The format of the data expected
7666 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
7667 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
7669 loadData : function(o, append){
7670 var r = this.reader.readRecords(o);
7671 this.loadRecords(r, {add: append}, true);
7675 * Gets the number of cached records.
7677 * <em>If using paging, this may not be the total size of the dataset. If the data object
7678 * used by the Reader contains the dataset size, then the getTotalCount() function returns
7679 * the data set size</em>
7681 getCount : function(){
7682 return this.data.length || 0;
7686 * Gets the total number of records in the dataset as returned by the server.
7688 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
7689 * the dataset size</em>
7691 getTotalCount : function(){
7692 return this.totalLength || 0;
7696 * Returns the sort state of the Store as an object with two properties:
7698 field {String} The name of the field by which the Records are sorted
7699 direction {String} The sort order, "ASC" or "DESC"
7702 getSortState : function(){
7703 return this.sortInfo;
7707 applySort : function(){
7708 if(this.sortInfo && !this.remoteSort){
7709 var s = this.sortInfo, f = s.field;
7710 var st = this.fields.get(f).sortType;
7711 var fn = function(r1, r2){
7712 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
7713 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
7715 this.data.sort(s.direction, fn);
7716 if(this.snapshot && this.snapshot != this.data){
7717 this.snapshot.sort(s.direction, fn);
7723 * Sets the default sort column and order to be used by the next load operation.
7724 * @param {String} fieldName The name of the field to sort by.
7725 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
7727 setDefaultSort : function(field, dir){
7728 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
7733 * If remote sorting is used, the sort is performed on the server, and the cache is
7734 * reloaded. If local sorting is used, the cache is sorted internally.
7735 * @param {String} fieldName The name of the field to sort by.
7736 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
7738 sort : function(fieldName, dir){
7739 var f = this.fields.get(fieldName);
7741 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
7743 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
7744 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
7749 this.sortToggle[f.name] = dir;
7750 this.sortInfo = {field: f.name, direction: dir};
7751 if(!this.remoteSort){
7753 this.fireEvent("datachanged", this);
7755 this.load(this.lastOptions);
7760 * Calls the specified function for each of the Records in the cache.
7761 * @param {Function} fn The function to call. The Record is passed as the first parameter.
7762 * Returning <em>false</em> aborts and exits the iteration.
7763 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
7765 each : function(fn, scope){
7766 this.data.each(fn, scope);
7770 * Gets all records modified since the last commit. Modified records are persisted across load operations
7771 * (e.g., during paging).
7772 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
7774 getModifiedRecords : function(){
7775 return this.modified;
7779 createFilterFn : function(property, value, anyMatch){
7780 if(!value.exec){ // not a regex
7781 value = String(value);
7782 if(value.length == 0){
7785 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
7788 return value.test(r.data[property]);
7793 * Sums the value of <i>property</i> for each record between start and end and returns the result.
7794 * @param {String} property A field on your records
7795 * @param {Number} start The record index to start at (defaults to 0)
7796 * @param {Number} end The last record index to include (defaults to length - 1)
7797 * @return {Number} The sum
7799 sum : function(property, start, end){
7800 var rs = this.data.items, v = 0;
7802 end = (end || end === 0) ? end : rs.length-1;
7804 for(var i = start; i <= end; i++){
7805 v += (rs[i].data[property] || 0);
7811 * Filter the records by a specified property.
7812 * @param {String} field A field on your records
7813 * @param {String/RegExp} value Either a string that the field
7814 * should start with or a RegExp to test against the field
7815 * @param {Boolean} anyMatch True to match any part not just the beginning
7817 filter : function(property, value, anyMatch){
7818 var fn = this.createFilterFn(property, value, anyMatch);
7819 return fn ? this.filterBy(fn) : this.clearFilter();
7823 * Filter by a function. The specified function will be called with each
7824 * record in this data source. If the function returns true the record is included,
7825 * otherwise it is filtered.
7826 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
7827 * @param {Object} scope (optional) The scope of the function (defaults to this)
7829 filterBy : function(fn, scope){
7830 this.snapshot = this.snapshot || this.data;
7831 this.data = this.queryBy(fn, scope||this);
7832 this.fireEvent("datachanged", this);
7836 * Query the records by a specified property.
7837 * @param {String} field A field on your records
7838 * @param {String/RegExp} value Either a string that the field
7839 * should start with or a RegExp to test against the field
7840 * @param {Boolean} anyMatch True to match any part not just the beginning
7841 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
7843 query : function(property, value, anyMatch){
7844 var fn = this.createFilterFn(property, value, anyMatch);
7845 return fn ? this.queryBy(fn) : this.data.clone();
7849 * Query by a function. The specified function will be called with each
7850 * record in this data source. If the function returns true the record is included
7852 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
7853 * @param {Object} scope (optional) The scope of the function (defaults to this)
7854 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
7856 queryBy : function(fn, scope){
7857 var data = this.snapshot || this.data;
7858 return data.filterBy(fn, scope||this);
7862 * Collects unique values for a particular dataIndex from this store.
7863 * @param {String} dataIndex The property to collect
7864 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
7865 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
7866 * @return {Array} An array of the unique values
7868 collect : function(dataIndex, allowNull, bypassFilter){
7869 var d = (bypassFilter === true && this.snapshot) ?
7870 this.snapshot.items : this.data.items;
7871 var v, sv, r = [], l = {};
7872 for(var i = 0, len = d.length; i < len; i++){
7873 v = d[i].data[dataIndex];
7875 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
7884 * Revert to a view of the Record cache with no filtering applied.
7885 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
7887 clearFilter : function(suppressEvent){
7888 if(this.snapshot && this.snapshot != this.data){
7889 this.data = this.snapshot;
7890 delete this.snapshot;
7891 if(suppressEvent !== true){
7892 this.fireEvent("datachanged", this);
7898 afterEdit : function(record){
7899 if(this.modified.indexOf(record) == -1){
7900 this.modified.push(record);
7902 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
7906 afterReject : function(record){
7907 this.modified.remove(record);
7908 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
7912 afterCommit : function(record){
7913 this.modified.remove(record);
7914 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
7918 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
7919 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
7921 commitChanges : function(){
7922 var m = this.modified.slice(0);
7924 for(var i = 0, len = m.length; i < len; i++){
7930 * Cancel outstanding changes on all changed records.
7932 rejectChanges : function(){
7933 var m = this.modified.slice(0);
7935 for(var i = 0, len = m.length; i < len; i++){
7940 onMetaChange : function(meta, rtype, o){
7941 this.recordType = rtype;
7942 this.fields = rtype.prototype.fields;
7943 delete this.snapshot;
7944 this.sortInfo = meta.sortInfo || this.sortInfo;
7946 this.fireEvent('metachange', this, this.reader.meta);
7949 moveIndex : function(data, type)
7951 var index = this.indexOf(data);
7953 var newIndex = index + type;
7957 this.insert(newIndex, data);
7962 * Ext JS Library 1.1.1
7963 * Copyright(c) 2006-2007, Ext JS, LLC.
7965 * Originally Released Under LGPL - original licence link has changed is not relivant.
7968 * <script type="text/javascript">
7972 * @class Roo.data.SimpleStore
7973 * @extends Roo.data.Store
7974 * Small helper class to make creating Stores from Array data easier.
7975 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
7976 * @cfg {Array} fields An array of field definition objects, or field name strings.
7977 * @cfg {Array} data The multi-dimensional array of data
7979 * @param {Object} config
7981 Roo.data.SimpleStore = function(config){
7982 Roo.data.SimpleStore.superclass.constructor.call(this, {
7984 reader: new Roo.data.ArrayReader({
7987 Roo.data.Record.create(config.fields)
7989 proxy : new Roo.data.MemoryProxy(config.data)
7993 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
7995 * Ext JS Library 1.1.1
7996 * Copyright(c) 2006-2007, Ext JS, LLC.
7998 * Originally Released Under LGPL - original licence link has changed is not relivant.
8001 * <script type="text/javascript">
8006 * @extends Roo.data.Store
8007 * @class Roo.data.JsonStore
8008 * Small helper class to make creating Stores for JSON data easier. <br/>
8010 var store = new Roo.data.JsonStore({
8011 url: 'get-images.php',
8013 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
8016 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
8017 * JsonReader and HttpProxy (unless inline data is provided).</b>
8018 * @cfg {Array} fields An array of field definition objects, or field name strings.
8020 * @param {Object} config
8022 Roo.data.JsonStore = function(c){
8023 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
8024 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
8025 reader: new Roo.data.JsonReader(c, c.fields)
8028 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
8030 * Ext JS Library 1.1.1
8031 * Copyright(c) 2006-2007, Ext JS, LLC.
8033 * Originally Released Under LGPL - original licence link has changed is not relivant.
8036 * <script type="text/javascript">
8040 Roo.data.Field = function(config){
8041 if(typeof config == "string"){
8042 config = {name: config};
8044 Roo.apply(this, config);
8050 var st = Roo.data.SortTypes;
8051 // named sortTypes are supported, here we look them up
8052 if(typeof this.sortType == "string"){
8053 this.sortType = st[this.sortType];
8056 // set default sortType for strings and dates
8060 this.sortType = st.asUCString;
8063 this.sortType = st.asDate;
8066 this.sortType = st.none;
8071 var stripRe = /[\$,%]/g;
8073 // prebuilt conversion function for this field, instead of
8074 // switching every time we're reading a value
8076 var cv, dateFormat = this.dateFormat;
8081 cv = function(v){ return v; };
8084 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
8088 return v !== undefined && v !== null && v !== '' ?
8089 parseInt(String(v).replace(stripRe, ""), 10) : '';
8094 return v !== undefined && v !== null && v !== '' ?
8095 parseFloat(String(v).replace(stripRe, ""), 10) : '';
8100 cv = function(v){ return v === true || v === "true" || v == 1; };
8107 if(v instanceof Date){
8111 if(dateFormat == "timestamp"){
8112 return new Date(v*1000);
8114 return Date.parseDate(v, dateFormat);
8116 var parsed = Date.parse(v);
8117 return parsed ? new Date(parsed) : null;
8126 Roo.data.Field.prototype = {
8134 * Ext JS Library 1.1.1
8135 * Copyright(c) 2006-2007, Ext JS, LLC.
8137 * Originally Released Under LGPL - original licence link has changed is not relivant.
8140 * <script type="text/javascript">
8143 // Base class for reading structured data from a data source. This class is intended to be
8144 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
8147 * @class Roo.data.DataReader
8148 * Base class for reading structured data from a data source. This class is intended to be
8149 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
8152 Roo.data.DataReader = function(meta, recordType){
8156 this.recordType = recordType instanceof Array ?
8157 Roo.data.Record.create(recordType) : recordType;
8160 Roo.data.DataReader.prototype = {
8162 * Create an empty record
8163 * @param {Object} data (optional) - overlay some values
8164 * @return {Roo.data.Record} record created.
8166 newRow : function(d) {
8168 this.recordType.prototype.fields.each(function(c) {
8170 case 'int' : da[c.name] = 0; break;
8171 case 'date' : da[c.name] = new Date(); break;
8172 case 'float' : da[c.name] = 0.0; break;
8173 case 'boolean' : da[c.name] = false; break;
8174 default : da[c.name] = ""; break;
8178 return new this.recordType(Roo.apply(da, d));
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 * @class Roo.data.DataProxy
8194 * @extends Roo.data.Observable
8195 * This class is an abstract base class for implementations which provide retrieval of
8196 * unformatted data objects.<br>
8198 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
8199 * (of the appropriate type which knows how to parse the data object) to provide a block of
8200 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
8202 * Custom implementations must implement the load method as described in
8203 * {@link Roo.data.HttpProxy#load}.
8205 Roo.data.DataProxy = function(){
8209 * Fires before a network request is made to retrieve a data object.
8210 * @param {Object} This DataProxy object.
8211 * @param {Object} params The params parameter to the load function.
8216 * Fires before the load method's callback is called.
8217 * @param {Object} This DataProxy object.
8218 * @param {Object} o The data object.
8219 * @param {Object} arg The callback argument object passed to the load function.
8223 * @event loadexception
8224 * Fires if an Exception occurs during data retrieval.
8225 * @param {Object} This DataProxy object.
8226 * @param {Object} o The data object.
8227 * @param {Object} arg The callback argument object passed to the load function.
8228 * @param {Object} e The Exception.
8230 loadexception : true
8232 Roo.data.DataProxy.superclass.constructor.call(this);
8235 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
8238 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
8242 * Ext JS Library 1.1.1
8243 * Copyright(c) 2006-2007, Ext JS, LLC.
8245 * Originally Released Under LGPL - original licence link has changed is not relivant.
8248 * <script type="text/javascript">
8251 * @class Roo.data.MemoryProxy
8252 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
8253 * to the Reader when its load method is called.
8255 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
8257 Roo.data.MemoryProxy = function(data){
8261 Roo.data.MemoryProxy.superclass.constructor.call(this);
8265 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
8267 * Load data from the requested source (in this case an in-memory
8268 * data object passed to the constructor), read the data object into
8269 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
8270 * process that block using the passed callback.
8271 * @param {Object} params This parameter is not used by the MemoryProxy class.
8272 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8273 * object into a block of Roo.data.Records.
8274 * @param {Function} callback The function into which to pass the block of Roo.data.records.
8275 * The function must be passed <ul>
8276 * <li>The Record block object</li>
8277 * <li>The "arg" argument from the load function</li>
8278 * <li>A boolean success indicator</li>
8280 * @param {Object} scope The scope in which to call the callback
8281 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8283 load : function(params, reader, callback, scope, arg){
8284 params = params || {};
8287 result = reader.readRecords(this.data);
8289 this.fireEvent("loadexception", this, arg, null, e);
8290 callback.call(scope, null, arg, false);
8293 callback.call(scope, result, arg, true);
8297 update : function(params, records){
8302 * Ext JS Library 1.1.1
8303 * Copyright(c) 2006-2007, Ext JS, LLC.
8305 * Originally Released Under LGPL - original licence link has changed is not relivant.
8308 * <script type="text/javascript">
8311 * @class Roo.data.HttpProxy
8312 * @extends Roo.data.DataProxy
8313 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
8314 * configured to reference a certain URL.<br><br>
8316 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
8317 * from which the running page was served.<br><br>
8319 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
8321 * Be aware that to enable the browser to parse an XML document, the server must set
8322 * the Content-Type header in the HTTP response to "text/xml".
8324 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
8325 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
8326 * will be used to make the request.
8328 Roo.data.HttpProxy = function(conn){
8329 Roo.data.HttpProxy.superclass.constructor.call(this);
8330 // is conn a conn config or a real conn?
8332 this.useAjax = !conn || !conn.events;
8336 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
8337 // thse are take from connection...
8340 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
8343 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
8344 * extra parameters to each request made by this object. (defaults to undefined)
8347 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
8348 * to each request made by this object. (defaults to undefined)
8351 * @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)
8354 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
8357 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
8363 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
8367 * Return the {@link Roo.data.Connection} object being used by this Proxy.
8368 * @return {Connection} The Connection object. This object may be used to subscribe to events on
8369 * a finer-grained basis than the DataProxy events.
8371 getConnection : function(){
8372 return this.useAjax ? Roo.Ajax : this.conn;
8376 * Load data from the configured {@link Roo.data.Connection}, read the data object into
8377 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
8378 * process that block using the passed callback.
8379 * @param {Object} params An object containing properties which are to be used as HTTP parameters
8380 * for the request to the remote server.
8381 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8382 * object into a block of Roo.data.Records.
8383 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
8384 * The function must be passed <ul>
8385 * <li>The Record block object</li>
8386 * <li>The "arg" argument from the load function</li>
8387 * <li>A boolean success indicator</li>
8389 * @param {Object} scope The scope in which to call the callback
8390 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8392 load : function(params, reader, callback, scope, arg){
8393 if(this.fireEvent("beforeload", this, params) !== false){
8395 params : params || {},
8397 callback : callback,
8402 callback : this.loadResponse,
8406 Roo.applyIf(o, this.conn);
8407 if(this.activeRequest){
8408 Roo.Ajax.abort(this.activeRequest);
8410 this.activeRequest = Roo.Ajax.request(o);
8412 this.conn.request(o);
8415 callback.call(scope||this, null, arg, false);
8420 loadResponse : function(o, success, response){
8421 delete this.activeRequest;
8423 this.fireEvent("loadexception", this, o, response);
8424 o.request.callback.call(o.request.scope, null, o.request.arg, false);
8429 result = o.reader.read(response);
8431 this.fireEvent("loadexception", this, o, response, e);
8432 o.request.callback.call(o.request.scope, null, o.request.arg, false);
8436 this.fireEvent("load", this, o, o.request.arg);
8437 o.request.callback.call(o.request.scope, result, o.request.arg, true);
8441 update : function(dataSet){
8446 updateResponse : function(dataSet){
8451 * Ext JS Library 1.1.1
8452 * Copyright(c) 2006-2007, Ext JS, LLC.
8454 * Originally Released Under LGPL - original licence link has changed is not relivant.
8457 * <script type="text/javascript">
8461 * @class Roo.data.ScriptTagProxy
8462 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
8463 * other than the originating domain of the running page.<br><br>
8465 * <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
8466 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
8468 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
8469 * source code that is used as the source inside a <script> tag.<br><br>
8471 * In order for the browser to process the returned data, the server must wrap the data object
8472 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
8473 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
8474 * depending on whether the callback name was passed:
8477 boolean scriptTag = false;
8478 String cb = request.getParameter("callback");
8481 response.setContentType("text/javascript");
8483 response.setContentType("application/x-json");
8485 Writer out = response.getWriter();
8487 out.write(cb + "(");
8489 out.print(dataBlock.toJsonString());
8496 * @param {Object} config A configuration object.
8498 Roo.data.ScriptTagProxy = function(config){
8499 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
8500 Roo.apply(this, config);
8501 this.head = document.getElementsByTagName("head")[0];
8504 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
8506 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
8508 * @cfg {String} url The URL from which to request the data object.
8511 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
8515 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
8516 * the server the name of the callback function set up by the load call to process the returned data object.
8517 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
8518 * javascript output which calls this named function passing the data object as its only parameter.
8520 callbackParam : "callback",
8522 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
8523 * name to the request.
8528 * Load data from the configured URL, read the data object into
8529 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
8530 * process that block using the passed callback.
8531 * @param {Object} params An object containing properties which are to be used as HTTP parameters
8532 * for the request to the remote server.
8533 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8534 * object into a block of Roo.data.Records.
8535 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
8536 * The function must be passed <ul>
8537 * <li>The Record block object</li>
8538 * <li>The "arg" argument from the load function</li>
8539 * <li>A boolean success indicator</li>
8541 * @param {Object} scope The scope in which to call the callback
8542 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8544 load : function(params, reader, callback, scope, arg){
8545 if(this.fireEvent("beforeload", this, params) !== false){
8547 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
8550 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
8552 url += "&_dc=" + (new Date().getTime());
8554 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
8557 cb : "stcCallback"+transId,
8558 scriptId : "stcScript"+transId,
8562 callback : callback,
8568 window[trans.cb] = function(o){
8569 conn.handleResponse(o, trans);
8572 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
8574 if(this.autoAbort !== false){
8578 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
8580 var script = document.createElement("script");
8581 script.setAttribute("src", url);
8582 script.setAttribute("type", "text/javascript");
8583 script.setAttribute("id", trans.scriptId);
8584 this.head.appendChild(script);
8588 callback.call(scope||this, null, arg, false);
8593 isLoading : function(){
8594 return this.trans ? true : false;
8598 * Abort the current server request.
8601 if(this.isLoading()){
8602 this.destroyTrans(this.trans);
8607 destroyTrans : function(trans, isLoaded){
8608 this.head.removeChild(document.getElementById(trans.scriptId));
8609 clearTimeout(trans.timeoutId);
8611 window[trans.cb] = undefined;
8613 delete window[trans.cb];
8616 // if hasn't been loaded, wait for load to remove it to prevent script error
8617 window[trans.cb] = function(){
8618 window[trans.cb] = undefined;
8620 delete window[trans.cb];
8627 handleResponse : function(o, trans){
8629 this.destroyTrans(trans, true);
8632 result = trans.reader.readRecords(o);
8634 this.fireEvent("loadexception", this, o, trans.arg, e);
8635 trans.callback.call(trans.scope||window, null, trans.arg, false);
8638 this.fireEvent("load", this, o, trans.arg);
8639 trans.callback.call(trans.scope||window, result, trans.arg, true);
8643 handleFailure : function(trans){
8645 this.destroyTrans(trans, false);
8646 this.fireEvent("loadexception", this, null, trans.arg);
8647 trans.callback.call(trans.scope||window, null, trans.arg, false);
8651 * Ext JS Library 1.1.1
8652 * Copyright(c) 2006-2007, Ext JS, LLC.
8654 * Originally Released Under LGPL - original licence link has changed is not relivant.
8657 * <script type="text/javascript">
8661 * @class Roo.data.JsonReader
8662 * @extends Roo.data.DataReader
8663 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
8664 * based on mappings in a provided Roo.data.Record constructor.
8666 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
8667 * in the reply previously.
8672 var RecordDef = Roo.data.Record.create([
8673 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
8674 {name: 'occupation'} // This field will use "occupation" as the mapping.
8676 var myReader = new Roo.data.JsonReader({
8677 totalProperty: "results", // The property which contains the total dataset size (optional)
8678 root: "rows", // The property which contains an Array of row objects
8679 id: "id" // The property within each row object that provides an ID for the record (optional)
8683 * This would consume a JSON file like this:
8685 { 'results': 2, 'rows': [
8686 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
8687 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
8690 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
8691 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
8692 * paged from the remote server.
8693 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
8694 * @cfg {String} root name of the property which contains the Array of row objects.
8695 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
8697 * Create a new JsonReader
8698 * @param {Object} meta Metadata configuration options
8699 * @param {Object} recordType Either an Array of field definition objects,
8700 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
8702 Roo.data.JsonReader = function(meta, recordType){
8705 // set some defaults:
8707 totalProperty: 'total',
8708 successProperty : 'success',
8713 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
8715 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
8718 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
8719 * Used by Store query builder to append _requestMeta to params.
8722 metaFromRemote : false,
8724 * This method is only used by a DataProxy which has retrieved data from a remote server.
8725 * @param {Object} response The XHR object which contains the JSON data in its responseText.
8726 * @return {Object} data A data block which is used by an Roo.data.Store object as
8727 * a cache of Roo.data.Records.
8729 read : function(response){
8730 var json = response.responseText;
8732 var o = /* eval:var:o */ eval("("+json+")");
8734 throw {message: "JsonReader.read: Json object not found"};
8740 this.metaFromRemote = true;
8741 this.meta = o.metaData;
8742 this.recordType = Roo.data.Record.create(o.metaData.fields);
8743 this.onMetaChange(this.meta, this.recordType, o);
8745 return this.readRecords(o);
8748 // private function a store will implement
8749 onMetaChange : function(meta, recordType, o){
8756 simpleAccess: function(obj, subsc) {
8763 getJsonAccessor: function(){
8765 return function(expr) {
8767 return(re.test(expr))
8768 ? new Function("obj", "return obj." + expr)
8778 * Create a data block containing Roo.data.Records from an XML document.
8779 * @param {Object} o An object which contains an Array of row objects in the property specified
8780 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
8781 * which contains the total size of the dataset.
8782 * @return {Object} data A data block which is used by an Roo.data.Store object as
8783 * a cache of Roo.data.Records.
8785 readRecords : function(o){
8787 * After any data loads, the raw JSON data is available for further custom processing.
8791 var s = this.meta, Record = this.recordType,
8792 f = Record.prototype.fields, fi = f.items, fl = f.length;
8794 // Generate extraction functions for the totalProperty, the root, the id, and for each field
8796 if(s.totalProperty) {
8797 this.getTotal = this.getJsonAccessor(s.totalProperty);
8799 if(s.successProperty) {
8800 this.getSuccess = this.getJsonAccessor(s.successProperty);
8802 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
8804 var g = this.getJsonAccessor(s.id);
8805 this.getId = function(rec) {
8807 return (r === undefined || r === "") ? null : r;
8810 this.getId = function(){return null;};
8813 for(var jj = 0; jj < fl; jj++){
8815 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
8816 this.ef[jj] = this.getJsonAccessor(map);
8820 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
8821 if(s.totalProperty){
8822 var vt = parseInt(this.getTotal(o), 10);
8827 if(s.successProperty){
8828 var vs = this.getSuccess(o);
8829 if(vs === false || vs === 'false'){
8834 for(var i = 0; i < c; i++){
8837 var id = this.getId(n);
8838 for(var j = 0; j < fl; j++){
8840 var v = this.ef[j](n);
8842 Roo.log('missing convert for ' + f.name);
8846 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
8848 var record = new Record(values, id);
8850 records[i] = record;
8856 totalRecords : totalRecords
8861 * Ext JS Library 1.1.1
8862 * Copyright(c) 2006-2007, Ext JS, LLC.
8864 * Originally Released Under LGPL - original licence link has changed is not relivant.
8867 * <script type="text/javascript">
8871 * @class Roo.data.ArrayReader
8872 * @extends Roo.data.DataReader
8873 * Data reader class to create an Array of Roo.data.Record objects from an Array.
8874 * Each element of that Array represents a row of data fields. The
8875 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
8876 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
8880 var RecordDef = Roo.data.Record.create([
8881 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
8882 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
8884 var myReader = new Roo.data.ArrayReader({
8885 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
8889 * This would consume an Array like this:
8891 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
8893 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
8895 * Create a new JsonReader
8896 * @param {Object} meta Metadata configuration options.
8897 * @param {Object} recordType Either an Array of field definition objects
8898 * as specified to {@link Roo.data.Record#create},
8899 * or an {@link Roo.data.Record} object
8900 * created using {@link Roo.data.Record#create}.
8902 Roo.data.ArrayReader = function(meta, recordType){
8903 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
8906 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
8908 * Create a data block containing Roo.data.Records from an XML document.
8909 * @param {Object} o An Array of row objects which represents the dataset.
8910 * @return {Object} data A data block which is used by an Roo.data.Store object as
8911 * a cache of Roo.data.Records.
8913 readRecords : function(o){
8914 var sid = this.meta ? this.meta.id : null;
8915 var recordType = this.recordType, fields = recordType.prototype.fields;
8918 for(var i = 0; i < root.length; i++){
8921 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
8922 for(var j = 0, jlen = fields.length; j < jlen; j++){
8923 var f = fields.items[j];
8924 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
8925 var v = n[k] !== undefined ? n[k] : f.defaultValue;
8929 var record = new recordType(values, id);
8931 records[records.length] = record;
8935 totalRecords : records.length
8944 * @class Roo.bootstrap.ComboBox
8945 * @extends Roo.bootstrap.TriggerField
8946 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
8947 * @cfg {Boolean} append (true|false) default false
8949 * Create a new ComboBox.
8950 * @param {Object} config Configuration options
8952 Roo.bootstrap.ComboBox = function(config){
8953 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
8957 * Fires when the dropdown list is expanded
8958 * @param {Roo.bootstrap.ComboBox} combo This combo box
8963 * Fires when the dropdown list is collapsed
8964 * @param {Roo.bootstrap.ComboBox} combo This combo box
8968 * @event beforeselect
8969 * Fires before a list item is selected. Return false to cancel the selection.
8970 * @param {Roo.bootstrap.ComboBox} combo This combo box
8971 * @param {Roo.data.Record} record The data record returned from the underlying store
8972 * @param {Number} index The index of the selected item in the dropdown list
8974 'beforeselect' : true,
8977 * Fires when a list item is selected
8978 * @param {Roo.bootstrap.ComboBox} combo This combo box
8979 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
8980 * @param {Number} index The index of the selected item in the dropdown list
8984 * @event beforequery
8985 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
8986 * The event object passed has these properties:
8987 * @param {Roo.bootstrap.ComboBox} combo This combo box
8988 * @param {String} query The query
8989 * @param {Boolean} forceAll true to force "all" query
8990 * @param {Boolean} cancel true to cancel the query
8991 * @param {Object} e The query event object
8993 'beforequery': true,
8996 * Fires when the 'add' icon is pressed (add a listener to enable add button)
8997 * @param {Roo.bootstrap.ComboBox} combo This combo box
9002 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
9003 * @param {Roo.bootstrap.ComboBox} combo This combo box
9004 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
9009 * Fires when the remove value from the combobox array
9010 * @param {Roo.bootstrap.ComboBox} combo This combo box
9017 this.selectedIndex = -1;
9018 if(this.mode == 'local'){
9019 if(config.queryDelay === undefined){
9020 this.queryDelay = 10;
9022 if(config.minChars === undefined){
9028 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
9031 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
9032 * rendering into an Roo.Editor, defaults to false)
9035 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
9036 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
9039 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
9042 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
9043 * the dropdown list (defaults to undefined, with no header element)
9047 * @cfg {String/Roo.Template} tpl The template to use to render the output
9051 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
9053 listWidth: undefined,
9055 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
9056 * mode = 'remote' or 'text' if mode = 'local')
9058 displayField: undefined,
9060 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
9061 * mode = 'remote' or 'value' if mode = 'local').
9062 * Note: use of a valueField requires the user make a selection
9063 * in order for a value to be mapped.
9065 valueField: undefined,
9069 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
9070 * field's data value (defaults to the underlying DOM element's name)
9072 hiddenName: undefined,
9074 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
9078 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
9080 selectedClass: 'active',
9083 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
9087 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
9088 * anchor positions (defaults to 'tl-bl')
9090 listAlign: 'tl-bl?',
9092 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
9096 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
9097 * query specified by the allQuery config option (defaults to 'query')
9099 triggerAction: 'query',
9101 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
9102 * (defaults to 4, does not apply if editable = false)
9106 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
9107 * delay (typeAheadDelay) if it matches a known value (defaults to false)
9111 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
9112 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
9116 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
9117 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
9121 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
9122 * when editable = true (defaults to false)
9124 selectOnFocus:false,
9126 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
9128 queryParam: 'query',
9130 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
9131 * when mode = 'remote' (defaults to 'Loading...')
9133 loadingText: 'Loading...',
9135 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
9139 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
9143 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
9144 * traditional select (defaults to true)
9148 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
9152 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
9156 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
9157 * listWidth has a higher value)
9161 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
9162 * allow the user to set arbitrary text into the field (defaults to false)
9164 forceSelection:false,
9166 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
9167 * if typeAhead = true (defaults to 250)
9169 typeAheadDelay : 250,
9171 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
9172 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
9174 valueNotFoundText : undefined,
9176 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
9181 * @cfg {Boolean} disableClear Disable showing of clear button.
9183 disableClear : false,
9185 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
9187 alwaysQuery : false,
9190 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
9204 // element that contains real text value.. (when hidden is used..)
9207 initEvents: function(){
9210 throw "can not find store for combo";
9212 this.store = Roo.factory(this.store, Roo.data);
9216 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
9219 if(this.hiddenName){
9221 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
9223 this.hiddenField.dom.value =
9224 this.hiddenValue !== undefined ? this.hiddenValue :
9225 this.value !== undefined ? this.value : '';
9227 // prevent input submission
9228 this.el.dom.removeAttribute('name');
9229 this.hiddenField.dom.setAttribute('name', this.hiddenName);
9234 // this.el.dom.setAttribute('autocomplete', 'off');
9237 var cls = 'x-combo-list';
9238 this.list = this.el.select('ul.dropdown-menu',true).first();
9240 //this.list = new Roo.Layer({
9241 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
9244 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
9245 this.list.setWidth(lw);
9247 this.list.on('mouseover', this.onViewOver, this);
9248 this.list.on('mousemove', this.onViewMove, this);
9250 this.list.on('scroll', this.onViewScroll, this);
9253 this.list.swallowEvent('mousewheel');
9254 this.assetHeight = 0;
9257 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
9258 this.assetHeight += this.header.getHeight();
9261 this.innerList = this.list.createChild({cls:cls+'-inner'});
9262 this.innerList.on('mouseover', this.onViewOver, this);
9263 this.innerList.on('mousemove', this.onViewMove, this);
9264 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
9266 if(this.allowBlank && !this.pageSize && !this.disableClear){
9267 this.footer = this.list.createChild({cls:cls+'-ft'});
9268 this.pageTb = new Roo.Toolbar(this.footer);
9272 this.footer = this.list.createChild({cls:cls+'-ft'});
9273 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
9274 {pageSize: this.pageSize});
9278 if (this.pageTb && this.allowBlank && !this.disableClear) {
9280 this.pageTb.add(new Roo.Toolbar.Fill(), {
9281 cls: 'x-btn-icon x-btn-clear',
9287 _this.onSelect(false, -1);
9292 this.assetHeight += this.footer.getHeight();
9297 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
9300 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
9301 singleSelect:true, store: this.store, selectedClass: this.selectedClass
9303 //this.view.wrapEl.setDisplayed(false);
9304 this.view.on('click', this.onViewClick, this);
9308 this.store.on('beforeload', this.onBeforeLoad, this);
9309 this.store.on('load', this.onLoad, this);
9310 this.store.on('loadexception', this.onLoadException, this);
9313 this.resizer = new Roo.Resizable(this.list, {
9314 pinned:true, handles:'se'
9316 this.resizer.on('resize', function(r, w, h){
9317 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
9319 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
9320 this.restrictHeight();
9322 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
9326 this.editable = true;
9327 this.setEditable(false);
9332 if (typeof(this.events.add.listeners) != 'undefined') {
9334 this.addicon = this.wrap.createChild(
9335 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
9337 this.addicon.on('click', function(e) {
9338 this.fireEvent('add', this);
9341 if (typeof(this.events.edit.listeners) != 'undefined') {
9343 this.editicon = this.wrap.createChild(
9344 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
9346 this.editicon.setStyle('margin-left', '40px');
9348 this.editicon.on('click', function(e) {
9350 // we fire even if inothing is selected..
9351 this.fireEvent('edit', this, this.lastData );
9357 this.keyNav = new Roo.KeyNav(this.inputEl(), {
9359 this.inKeyMode = true;
9363 "down" : function(e){
9364 if(!this.isExpanded()){
9365 this.onTriggerClick();
9367 this.inKeyMode = true;
9372 "enter" : function(e){
9377 "esc" : function(e){
9381 "tab" : function(e){
9384 if(this.fireEvent("specialkey", this, e)){
9385 this.onViewClick(false);
9393 doRelay : function(foo, bar, hname){
9394 if(hname == 'down' || this.scope.isExpanded()){
9395 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
9404 this.queryDelay = Math.max(this.queryDelay || 10,
9405 this.mode == 'local' ? 10 : 250);
9408 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
9411 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
9413 if(this.editable !== false){
9414 this.inputEl().on("keyup", this.onKeyUp, this);
9416 if(this.forceSelection){
9417 this.inputEl().on('blur', this.doForce, this);
9421 this.choices = this.el.select('ul.select2-choices', true).first();
9422 this.searchField = this.el.select('ul li.select2-search-field', true).first();
9426 onDestroy : function(){
9428 this.view.setStore(null);
9429 this.view.el.removeAllListeners();
9430 this.view.el.remove();
9431 this.view.purgeListeners();
9434 this.list.dom.innerHTML = '';
9437 this.store.un('beforeload', this.onBeforeLoad, this);
9438 this.store.un('load', this.onLoad, this);
9439 this.store.un('loadexception', this.onLoadException, this);
9441 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
9445 fireKey : function(e){
9446 if(e.isNavKeyPress() && !this.list.isVisible()){
9447 this.fireEvent("specialkey", this, e);
9452 onResize: function(w, h){
9453 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
9455 // if(typeof w != 'number'){
9456 // // we do not handle it!?!?
9459 // var tw = this.trigger.getWidth();
9460 // // tw += this.addicon ? this.addicon.getWidth() : 0;
9461 // // tw += this.editicon ? this.editicon.getWidth() : 0;
9463 // this.inputEl().setWidth( this.adjustWidth('input', x));
9465 // //this.trigger.setStyle('left', x+'px');
9467 // if(this.list && this.listWidth === undefined){
9468 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
9469 // this.list.setWidth(lw);
9470 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
9478 * Allow or prevent the user from directly editing the field text. If false is passed,
9479 * the user will only be able to select from the items defined in the dropdown list. This method
9480 * is the runtime equivalent of setting the 'editable' config option at config time.
9481 * @param {Boolean} value True to allow the user to directly edit the field text
9483 setEditable : function(value){
9484 if(value == this.editable){
9487 this.editable = value;
9489 this.inputEl().dom.setAttribute('readOnly', true);
9490 this.inputEl().on('mousedown', this.onTriggerClick, this);
9491 this.inputEl().addClass('x-combo-noedit');
9493 this.inputEl().dom.setAttribute('readOnly', false);
9494 this.inputEl().un('mousedown', this.onTriggerClick, this);
9495 this.inputEl().removeClass('x-combo-noedit');
9501 onBeforeLoad : function(combo,opts){
9506 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
9508 this.restrictHeight();
9509 this.selectedIndex = -1;
9513 onLoad : function(){
9515 this.hasQuery = false;
9521 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
9522 this.loading.hide();
9525 if(this.store.getCount() > 0){
9527 this.restrictHeight();
9528 if(this.lastQuery == this.allQuery){
9530 this.inputEl().dom.select();
9532 if(!this.selectByValue(this.value, true)){
9533 this.select(0, true);
9537 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
9538 this.taTask.delay(this.typeAheadDelay);
9542 this.onEmptyResults();
9548 onLoadException : function()
9550 this.hasQuery = false;
9552 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
9553 this.loading.hide();
9557 Roo.log(this.store.reader.jsonData);
9558 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
9560 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
9566 onTypeAhead : function(){
9567 if(this.store.getCount() > 0){
9568 var r = this.store.getAt(0);
9569 var newValue = r.data[this.displayField];
9570 var len = newValue.length;
9571 var selStart = this.getRawValue().length;
9573 if(selStart != len){
9574 this.setRawValue(newValue);
9575 this.selectText(selStart, newValue.length);
9581 onSelect : function(record, index){
9583 if(this.fireEvent('beforeselect', this, record, index) !== false){
9585 this.setFromData(index > -1 ? record.data : false);
9588 this.fireEvent('select', this, record, index);
9593 * Returns the currently selected field value or empty string if no value is set.
9594 * @return {String} value The selected value
9596 getValue : function(){
9599 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
9602 if(this.valueField){
9603 return typeof this.value != 'undefined' ? this.value : '';
9605 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
9610 * Clears any text/value currently set in the field
9612 clearValue : function(){
9613 if(this.hiddenField){
9614 this.hiddenField.dom.value = '';
9617 this.setRawValue('');
9618 this.lastSelectionText = '';
9623 * Sets the specified value into the field. If the value finds a match, the corresponding record text
9624 * will be displayed in the field. If the value does not match the data value of an existing item,
9625 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
9626 * Otherwise the field will be blank (although the value will still be set).
9627 * @param {String} value The value to match
9629 setValue : function(v){
9636 if(this.valueField){
9637 var r = this.findRecord(this.valueField, v);
9639 text = r.data[this.displayField];
9640 }else if(this.valueNotFoundText !== undefined){
9641 text = this.valueNotFoundText;
9644 this.lastSelectionText = text;
9645 if(this.hiddenField){
9646 this.hiddenField.dom.value = v;
9648 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
9652 * @property {Object} the last set data for the element
9657 * Sets the value of the field based on a object which is related to the record format for the store.
9658 * @param {Object} value the value to set as. or false on reset?
9660 setFromData : function(o){
9667 var dv = ''; // display value
9668 var vv = ''; // value value..
9670 if (this.displayField) {
9671 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
9673 // this is an error condition!!!
9674 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
9677 if(this.valueField){
9678 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
9681 if(this.hiddenField){
9682 this.hiddenField.dom.value = vv;
9684 this.lastSelectionText = dv;
9685 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
9689 // no hidden field.. - we store the value in 'value', but still display
9690 // display field!!!!
9691 this.lastSelectionText = dv;
9692 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
9699 // overridden so that last data is reset..
9700 this.setValue(this.originalValue);
9701 this.clearInvalid();
9702 this.lastData = false;
9704 this.view.clearSelections();
9708 findRecord : function(prop, value){
9710 if(this.store.getCount() > 0){
9711 this.store.each(function(r){
9712 if(r.data[prop] == value){
9724 // returns hidden if it's set..
9725 if (!this.rendered) {return ''};
9726 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
9730 onViewMove : function(e, t){
9731 this.inKeyMode = false;
9735 onViewOver : function(e, t){
9736 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
9739 var item = this.view.findItemFromChild(t);
9741 var index = this.view.indexOf(item);
9742 this.select(index, false);
9747 onViewClick : function(doFocus)
9749 var index = this.view.getSelectedIndexes()[0];
9750 var r = this.store.getAt(index);
9752 this.onSelect(r, index);
9754 if(doFocus !== false && !this.blockFocus){
9755 this.inputEl().focus();
9760 restrictHeight : function(){
9761 //this.innerList.dom.style.height = '';
9762 //var inner = this.innerList.dom;
9763 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
9764 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
9765 //this.list.beginUpdate();
9766 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
9767 this.list.alignTo(this.inputEl(), this.listAlign);
9768 //this.list.endUpdate();
9772 onEmptyResults : function(){
9777 * Returns true if the dropdown list is expanded, else false.
9779 isExpanded : function(){
9780 return this.list.isVisible();
9784 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
9785 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
9786 * @param {String} value The data value of the item to select
9787 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
9788 * selected item if it is not currently in view (defaults to true)
9789 * @return {Boolean} True if the value matched an item in the list, else false
9791 selectByValue : function(v, scrollIntoView){
9792 if(v !== undefined && v !== null){
9793 var r = this.findRecord(this.valueField || this.displayField, v);
9795 this.select(this.store.indexOf(r), scrollIntoView);
9803 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
9804 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
9805 * @param {Number} index The zero-based index of the list item to select
9806 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
9807 * selected item if it is not currently in view (defaults to true)
9809 select : function(index, scrollIntoView){
9810 this.selectedIndex = index;
9811 this.view.select(index);
9812 if(scrollIntoView !== false){
9813 var el = this.view.getNode(index);
9815 //this.innerList.scrollChildIntoView(el, false);
9822 selectNext : function(){
9823 var ct = this.store.getCount();
9825 if(this.selectedIndex == -1){
9827 }else if(this.selectedIndex < ct-1){
9828 this.select(this.selectedIndex+1);
9834 selectPrev : function(){
9835 var ct = this.store.getCount();
9837 if(this.selectedIndex == -1){
9839 }else if(this.selectedIndex != 0){
9840 this.select(this.selectedIndex-1);
9846 onKeyUp : function(e){
9847 if(this.editable !== false && !e.isSpecialKey()){
9848 this.lastKey = e.getKey();
9849 this.dqTask.delay(this.queryDelay);
9854 validateBlur : function(){
9855 return !this.list || !this.list.isVisible();
9859 initQuery : function(){
9860 this.doQuery(this.getRawValue());
9864 doForce : function(){
9865 if(this.inputEl().dom.value.length > 0){
9866 this.inputEl().dom.value =
9867 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
9873 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
9874 * query allowing the query action to be canceled if needed.
9875 * @param {String} query The SQL query to execute
9876 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
9877 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
9878 * saved in the current store (defaults to false)
9880 doQuery : function(q, forceAll){
9882 if(q === undefined || q === null){
9891 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
9896 forceAll = qe.forceAll;
9897 if(forceAll === true || (q.length >= this.minChars)){
9899 this.hasQuery = true;
9901 if(this.lastQuery != q || this.alwaysQuery){
9903 if(this.mode == 'local'){
9904 this.selectedIndex = -1;
9906 this.store.clearFilter();
9908 this.store.filter(this.displayField, q);
9912 this.store.baseParams[this.queryParam] = q;
9914 var options = {params : this.getParams(q)};
9918 options.params.start = this.page * this.pageSize;
9921 this.store.load(options);
9925 this.selectedIndex = -1;
9930 this.loadNext = false;
9934 getParams : function(q){
9936 //p[this.queryParam] = q;
9940 p.limit = this.pageSize;
9946 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
9948 collapse : function(){
9949 if(!this.isExpanded()){
9954 Roo.get(document).un('mousedown', this.collapseIf, this);
9955 Roo.get(document).un('mousewheel', this.collapseIf, this);
9956 if (!this.editable) {
9957 Roo.get(document).un('keydown', this.listKeyPress, this);
9959 this.fireEvent('collapse', this);
9963 collapseIf : function(e){
9964 var in_combo = e.within(this.el);
9965 var in_list = e.within(this.list);
9967 if (in_combo || in_list) {
9968 //e.stopPropagation();
9977 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
9979 expand : function(){
9981 if(this.isExpanded() || !this.hasFocus){
9985 this.list.alignTo(this.inputEl(), this.listAlign);
9987 Roo.get(document).on('mousedown', this.collapseIf, this);
9988 Roo.get(document).on('mousewheel', this.collapseIf, this);
9989 if (!this.editable) {
9990 Roo.get(document).on('keydown', this.listKeyPress, this);
9993 this.fireEvent('expand', this);
9997 // Implements the default empty TriggerField.onTriggerClick function
9998 onTriggerClick : function()
10000 Roo.log('trigger click');
10007 this.loadNext = false;
10009 if(this.isExpanded()){
10011 if (!this.blockFocus) {
10012 this.inputEl().focus();
10016 this.hasFocus = true;
10017 if(this.triggerAction == 'all') {
10018 this.doQuery(this.allQuery, true);
10020 this.doQuery(this.getRawValue());
10022 if (!this.blockFocus) {
10023 this.inputEl().focus();
10027 listKeyPress : function(e)
10029 //Roo.log('listkeypress');
10030 // scroll to first matching element based on key pres..
10031 if (e.isSpecialKey()) {
10034 var k = String.fromCharCode(e.getKey()).toUpperCase();
10037 var csel = this.view.getSelectedNodes();
10038 var cselitem = false;
10040 var ix = this.view.indexOf(csel[0]);
10041 cselitem = this.store.getAt(ix);
10042 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
10048 this.store.each(function(v) {
10050 // start at existing selection.
10051 if (cselitem.id == v.id) {
10057 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
10058 match = this.store.indexOf(v);
10064 if (match === false) {
10065 return true; // no more action?
10068 this.view.select(match);
10069 var sn = Roo.get(this.view.getSelectedNodes()[0])
10070 //sn.scrollIntoView(sn.dom.parentNode, false);
10073 onViewScroll : function(e, t){
10075 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
10079 this.hasQuery = true;
10081 this.loading = this.list.select('.loading', true).first();
10083 if(this.loading === null){
10084 this.list.createChild({
10086 cls: 'loading select2-more-results select2-active',
10087 html: 'Loading more results...'
10090 this.loading = this.list.select('.loading', true).first();
10092 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
10094 this.loading.hide();
10097 this.loading.show();
10102 this.loadNext = true;
10104 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
10109 addItem : function(o)
10111 var dv = ''; // display value
10113 if (this.displayField) {
10114 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
10116 // this is an error condition!!!
10117 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
10124 var choice = this.choices.createChild({
10126 cls: 'select2-search-choice',
10135 cls: 'select2-search-choice-close',
10140 }, this.searchField);
10142 var close = choice.select('a.select2-search-choice-close', true).first()
10144 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
10151 this.inputEl().dom.value = '';
10155 onRemoveItem : function(e, _self, o)
10157 e.preventDefault();
10158 var index = this.item.indexOf(o.data) * 1;
10161 Roo.log('not this item?!');
10165 this.item.splice(index, 1);
10170 this.fireEvent('remove', this, e);
10174 syncValue : function()
10176 if(!this.item.length){
10183 Roo.each(this.item, function(i){
10184 if(_this.valueField){
10185 value.push(i[_this.valueField]);
10192 this.value = value.join(',');
10194 if(this.hiddenField){
10195 this.hiddenField.dom.value = this.value;
10199 clearItem : function()
10201 if(!this.multiple){
10207 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
10217 * @cfg {Boolean} grow
10221 * @cfg {Number} growMin
10225 * @cfg {Number} growMax
10235 * Ext JS Library 1.1.1
10236 * Copyright(c) 2006-2007, Ext JS, LLC.
10238 * Originally Released Under LGPL - original licence link has changed is not relivant.
10241 * <script type="text/javascript">
10246 * @extends Roo.util.Observable
10247 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
10248 * This class also supports single and multi selection modes. <br>
10249 * Create a data model bound view:
10251 var store = new Roo.data.Store(...);
10253 var view = new Roo.View({
10255 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
10257 singleSelect: true,
10258 selectedClass: "ydataview-selected",
10262 // listen for node click?
10263 view.on("click", function(vw, index, node, e){
10264 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
10268 dataModel.load("foobar.xml");
10270 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
10272 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
10273 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
10275 * Note: old style constructor is still suported (container, template, config)
10278 * Create a new View
10279 * @param {Object} config The config object
10282 Roo.View = function(config, depreciated_tpl, depreciated_config){
10284 if (typeof(depreciated_tpl) == 'undefined') {
10285 // new way.. - universal constructor.
10286 Roo.apply(this, config);
10287 this.el = Roo.get(this.el);
10290 this.el = Roo.get(config);
10291 this.tpl = depreciated_tpl;
10292 Roo.apply(this, depreciated_config);
10294 this.wrapEl = this.el.wrap().wrap();
10295 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
10298 if(typeof(this.tpl) == "string"){
10299 this.tpl = new Roo.Template(this.tpl);
10301 // support xtype ctors..
10302 this.tpl = new Roo.factory(this.tpl, Roo);
10306 this.tpl.compile();
10314 * @event beforeclick
10315 * Fires before a click is processed. Returns false to cancel the default action.
10316 * @param {Roo.View} this
10317 * @param {Number} index The index of the target node
10318 * @param {HTMLElement} node The target node
10319 * @param {Roo.EventObject} e The raw event object
10321 "beforeclick" : true,
10324 * Fires when a template node is clicked.
10325 * @param {Roo.View} this
10326 * @param {Number} index The index of the target node
10327 * @param {HTMLElement} node The target node
10328 * @param {Roo.EventObject} e The raw event object
10333 * Fires when a template node is double clicked.
10334 * @param {Roo.View} this
10335 * @param {Number} index The index of the target node
10336 * @param {HTMLElement} node The target node
10337 * @param {Roo.EventObject} e The raw event object
10341 * @event contextmenu
10342 * Fires when a template node is right clicked.
10343 * @param {Roo.View} this
10344 * @param {Number} index The index of the target node
10345 * @param {HTMLElement} node The target node
10346 * @param {Roo.EventObject} e The raw event object
10348 "contextmenu" : true,
10350 * @event selectionchange
10351 * Fires when the selected nodes change.
10352 * @param {Roo.View} this
10353 * @param {Array} selections Array of the selected nodes
10355 "selectionchange" : true,
10358 * @event beforeselect
10359 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
10360 * @param {Roo.View} this
10361 * @param {HTMLElement} node The node to be selected
10362 * @param {Array} selections Array of currently selected nodes
10364 "beforeselect" : true,
10366 * @event preparedata
10367 * Fires on every row to render, to allow you to change the data.
10368 * @param {Roo.View} this
10369 * @param {Object} data to be rendered (change this)
10371 "preparedata" : true
10379 "click": this.onClick,
10380 "dblclick": this.onDblClick,
10381 "contextmenu": this.onContextMenu,
10385 this.selections = [];
10387 this.cmp = new Roo.CompositeElementLite([]);
10389 this.store = Roo.factory(this.store, Roo.data);
10390 this.setStore(this.store, true);
10393 if ( this.footer && this.footer.xtype) {
10395 var fctr = this.wrapEl.appendChild(document.createElement("div"));
10397 this.footer.dataSource = this.store
10398 this.footer.container = fctr;
10399 this.footer = Roo.factory(this.footer, Roo);
10400 fctr.insertFirst(this.el);
10402 // this is a bit insane - as the paging toolbar seems to detach the el..
10403 // dom.parentNode.parentNode.parentNode
10404 // they get detached?
10408 Roo.View.superclass.constructor.call(this);
10413 Roo.extend(Roo.View, Roo.util.Observable, {
10416 * @cfg {Roo.data.Store} store Data store to load data from.
10421 * @cfg {String|Roo.Element} el The container element.
10426 * @cfg {String|Roo.Template} tpl The template used by this View
10430 * @cfg {String} dataName the named area of the template to use as the data area
10431 * Works with domtemplates roo-name="name"
10435 * @cfg {String} selectedClass The css class to add to selected nodes
10437 selectedClass : "x-view-selected",
10439 * @cfg {String} emptyText The empty text to show when nothing is loaded.
10444 * @cfg {String} text to display on mask (default Loading)
10448 * @cfg {Boolean} multiSelect Allow multiple selection
10450 multiSelect : false,
10452 * @cfg {Boolean} singleSelect Allow single selection
10454 singleSelect: false,
10457 * @cfg {Boolean} toggleSelect - selecting
10459 toggleSelect : false,
10462 * Returns the element this view is bound to.
10463 * @return {Roo.Element}
10465 getEl : function(){
10466 return this.wrapEl;
10472 * Refreshes the view. - called by datachanged on the store. - do not call directly.
10474 refresh : function(){
10475 Roo.log('refresh');
10478 // if we are using something like 'domtemplate', then
10479 // the what gets used is:
10480 // t.applySubtemplate(NAME, data, wrapping data..)
10481 // the outer template then get' applied with
10482 // the store 'extra data'
10483 // and the body get's added to the
10484 // roo-name="data" node?
10485 // <span class='roo-tpl-{name}'></span> ?????
10489 this.clearSelections();
10490 this.el.update("");
10492 var records = this.store.getRange();
10493 if(records.length < 1) {
10495 // is this valid?? = should it render a template??
10497 this.el.update(this.emptyText);
10501 if (this.dataName) {
10502 this.el.update(t.apply(this.store.meta)); //????
10503 el = this.el.child('.roo-tpl-' + this.dataName);
10506 for(var i = 0, len = records.length; i < len; i++){
10507 var data = this.prepareData(records[i].data, i, records[i]);
10508 this.fireEvent("preparedata", this, data, i, records[i]);
10509 html[html.length] = Roo.util.Format.trim(
10511 t.applySubtemplate(this.dataName, data, this.store.meta) :
10518 el.update(html.join(""));
10519 this.nodes = el.dom.childNodes;
10520 this.updateIndexes(0);
10525 * Function to override to reformat the data that is sent to
10526 * the template for each node.
10527 * DEPRICATED - use the preparedata event handler.
10528 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
10529 * a JSON object for an UpdateManager bound view).
10531 prepareData : function(data, index, record)
10533 this.fireEvent("preparedata", this, data, index, record);
10537 onUpdate : function(ds, record){
10538 Roo.log('on update');
10539 this.clearSelections();
10540 var index = this.store.indexOf(record);
10541 var n = this.nodes[index];
10542 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
10543 n.parentNode.removeChild(n);
10544 this.updateIndexes(index, index);
10550 onAdd : function(ds, records, index)
10552 Roo.log(['on Add', ds, records, index] );
10553 this.clearSelections();
10554 if(this.nodes.length == 0){
10558 var n = this.nodes[index];
10559 for(var i = 0, len = records.length; i < len; i++){
10560 var d = this.prepareData(records[i].data, i, records[i]);
10562 this.tpl.insertBefore(n, d);
10565 this.tpl.append(this.el, d);
10568 this.updateIndexes(index);
10571 onRemove : function(ds, record, index){
10572 Roo.log('onRemove');
10573 this.clearSelections();
10574 var el = this.dataName ?
10575 this.el.child('.roo-tpl-' + this.dataName) :
10578 el.dom.removeChild(this.nodes[index]);
10579 this.updateIndexes(index);
10583 * Refresh an individual node.
10584 * @param {Number} index
10586 refreshNode : function(index){
10587 this.onUpdate(this.store, this.store.getAt(index));
10590 updateIndexes : function(startIndex, endIndex){
10591 var ns = this.nodes;
10592 startIndex = startIndex || 0;
10593 endIndex = endIndex || ns.length - 1;
10594 for(var i = startIndex; i <= endIndex; i++){
10595 ns[i].nodeIndex = i;
10600 * Changes the data store this view uses and refresh the view.
10601 * @param {Store} store
10603 setStore : function(store, initial){
10604 if(!initial && this.store){
10605 this.store.un("datachanged", this.refresh);
10606 this.store.un("add", this.onAdd);
10607 this.store.un("remove", this.onRemove);
10608 this.store.un("update", this.onUpdate);
10609 this.store.un("clear", this.refresh);
10610 this.store.un("beforeload", this.onBeforeLoad);
10611 this.store.un("load", this.onLoad);
10612 this.store.un("loadexception", this.onLoad);
10616 store.on("datachanged", this.refresh, this);
10617 store.on("add", this.onAdd, this);
10618 store.on("remove", this.onRemove, this);
10619 store.on("update", this.onUpdate, this);
10620 store.on("clear", this.refresh, this);
10621 store.on("beforeload", this.onBeforeLoad, this);
10622 store.on("load", this.onLoad, this);
10623 store.on("loadexception", this.onLoad, this);
10631 * onbeforeLoad - masks the loading area.
10634 onBeforeLoad : function(store,opts)
10636 Roo.log('onBeforeLoad');
10638 this.el.update("");
10640 this.el.mask(this.mask ? this.mask : "Loading" );
10642 onLoad : function ()
10649 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
10650 * @param {HTMLElement} node
10651 * @return {HTMLElement} The template node
10653 findItemFromChild : function(node){
10654 var el = this.dataName ?
10655 this.el.child('.roo-tpl-' + this.dataName,true) :
10658 if(!node || node.parentNode == el){
10661 var p = node.parentNode;
10662 while(p && p != el){
10663 if(p.parentNode == el){
10672 onClick : function(e){
10673 var item = this.findItemFromChild(e.getTarget());
10675 var index = this.indexOf(item);
10676 if(this.onItemClick(item, index, e) !== false){
10677 this.fireEvent("click", this, index, item, e);
10680 this.clearSelections();
10685 onContextMenu : function(e){
10686 var item = this.findItemFromChild(e.getTarget());
10688 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
10693 onDblClick : function(e){
10694 var item = this.findItemFromChild(e.getTarget());
10696 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
10700 onItemClick : function(item, index, e)
10702 if(this.fireEvent("beforeclick", this, index, item, e) === false){
10705 if (this.toggleSelect) {
10706 var m = this.isSelected(item) ? 'unselect' : 'select';
10709 _t[m](item, true, false);
10712 if(this.multiSelect || this.singleSelect){
10713 if(this.multiSelect && e.shiftKey && this.lastSelection){
10714 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
10716 this.select(item, this.multiSelect && e.ctrlKey);
10717 this.lastSelection = item;
10719 e.preventDefault();
10725 * Get the number of selected nodes.
10728 getSelectionCount : function(){
10729 return this.selections.length;
10733 * Get the currently selected nodes.
10734 * @return {Array} An array of HTMLElements
10736 getSelectedNodes : function(){
10737 return this.selections;
10741 * Get the indexes of the selected nodes.
10744 getSelectedIndexes : function(){
10745 var indexes = [], s = this.selections;
10746 for(var i = 0, len = s.length; i < len; i++){
10747 indexes.push(s[i].nodeIndex);
10753 * Clear all selections
10754 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
10756 clearSelections : function(suppressEvent){
10757 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
10758 this.cmp.elements = this.selections;
10759 this.cmp.removeClass(this.selectedClass);
10760 this.selections = [];
10761 if(!suppressEvent){
10762 this.fireEvent("selectionchange", this, this.selections);
10768 * Returns true if the passed node is selected
10769 * @param {HTMLElement/Number} node The node or node index
10770 * @return {Boolean}
10772 isSelected : function(node){
10773 var s = this.selections;
10777 node = this.getNode(node);
10778 return s.indexOf(node) !== -1;
10783 * @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
10784 * @param {Boolean} keepExisting (optional) true to keep existing selections
10785 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
10787 select : function(nodeInfo, keepExisting, suppressEvent){
10788 if(nodeInfo instanceof Array){
10790 this.clearSelections(true);
10792 for(var i = 0, len = nodeInfo.length; i < len; i++){
10793 this.select(nodeInfo[i], true, true);
10797 var node = this.getNode(nodeInfo);
10798 if(!node || this.isSelected(node)){
10799 return; // already selected.
10802 this.clearSelections(true);
10804 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
10805 Roo.fly(node).addClass(this.selectedClass);
10806 this.selections.push(node);
10807 if(!suppressEvent){
10808 this.fireEvent("selectionchange", this, this.selections);
10816 * @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
10817 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
10818 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
10820 unselect : function(nodeInfo, keepExisting, suppressEvent)
10822 if(nodeInfo instanceof Array){
10823 Roo.each(this.selections, function(s) {
10824 this.unselect(s, nodeInfo);
10828 var node = this.getNode(nodeInfo);
10829 if(!node || !this.isSelected(node)){
10830 Roo.log("not selected");
10831 return; // not selected.
10835 Roo.each(this.selections, function(s) {
10837 Roo.fly(node).removeClass(this.selectedClass);
10844 this.selections= ns;
10845 this.fireEvent("selectionchange", this, this.selections);
10849 * Gets a template node.
10850 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
10851 * @return {HTMLElement} The node or null if it wasn't found
10853 getNode : function(nodeInfo){
10854 if(typeof nodeInfo == "string"){
10855 return document.getElementById(nodeInfo);
10856 }else if(typeof nodeInfo == "number"){
10857 return this.nodes[nodeInfo];
10863 * Gets a range template nodes.
10864 * @param {Number} startIndex
10865 * @param {Number} endIndex
10866 * @return {Array} An array of nodes
10868 getNodes : function(start, end){
10869 var ns = this.nodes;
10870 start = start || 0;
10871 end = typeof end == "undefined" ? ns.length - 1 : end;
10874 for(var i = start; i <= end; i++){
10878 for(var i = start; i >= end; i--){
10886 * Finds the index of the passed node
10887 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
10888 * @return {Number} The index of the node or -1
10890 indexOf : function(node){
10891 node = this.getNode(node);
10892 if(typeof node.nodeIndex == "number"){
10893 return node.nodeIndex;
10895 var ns = this.nodes;
10896 for(var i = 0, len = ns.length; i < len; i++){
10907 * based on jquery fullcalendar
10911 Roo.bootstrap = Roo.bootstrap || {};
10913 * @class Roo.bootstrap.Calendar
10914 * @extends Roo.bootstrap.Component
10915 * Bootstrap Calendar class
10916 * @cfg {Boolean} loadMask (true|false) default false
10917 * @cfg {Object} header generate the user specific header of the calendar, default false
10920 * Create a new Container
10921 * @param {Object} config The config object
10926 Roo.bootstrap.Calendar = function(config){
10927 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
10931 * Fires when a date is selected
10932 * @param {DatePicker} this
10933 * @param {Date} date The selected date
10937 * @event monthchange
10938 * Fires when the displayed month changes
10939 * @param {DatePicker} this
10940 * @param {Date} date The selected month
10942 'monthchange': true,
10944 * @event evententer
10945 * Fires when mouse over an event
10946 * @param {Calendar} this
10947 * @param {event} Event
10949 'evententer': true,
10951 * @event eventleave
10952 * Fires when the mouse leaves an
10953 * @param {Calendar} this
10956 'eventleave': true,
10958 * @event eventclick
10959 * Fires when the mouse click an
10960 * @param {Calendar} this
10969 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
10972 * @cfg {Number} startDay
10973 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
10981 getAutoCreate : function(){
10984 var fc_button = function(name, corner, style, content ) {
10985 return Roo.apply({},{
10987 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
10989 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
10992 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
11003 style : 'width:100%',
11010 cls : 'fc-header-left',
11012 fc_button('prev', 'left', 'arrow', '‹' ),
11013 fc_button('next', 'right', 'arrow', '›' ),
11014 { tag: 'span', cls: 'fc-header-space' },
11015 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
11023 cls : 'fc-header-center',
11027 cls: 'fc-header-title',
11030 html : 'month / year'
11038 cls : 'fc-header-right',
11040 /* fc_button('month', 'left', '', 'month' ),
11041 fc_button('week', '', '', 'week' ),
11042 fc_button('day', 'right', '', 'day' )
11054 header = this.header;
11057 var cal_heads = function() {
11059 // fixme - handle this.
11061 for (var i =0; i < Date.dayNames.length; i++) {
11062 var d = Date.dayNames[i];
11065 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
11066 html : d.substring(0,3)
11070 ret[0].cls += ' fc-first';
11071 ret[6].cls += ' fc-last';
11074 var cal_cell = function(n) {
11077 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
11082 cls: 'fc-day-number',
11086 cls: 'fc-day-content',
11090 style: 'position: relative;' // height: 17px;
11102 var cal_rows = function() {
11105 for (var r = 0; r < 6; r++) {
11112 for (var i =0; i < Date.dayNames.length; i++) {
11113 var d = Date.dayNames[i];
11114 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
11117 row.cn[0].cls+=' fc-first';
11118 row.cn[0].cn[0].style = 'min-height:90px';
11119 row.cn[6].cls+=' fc-last';
11123 ret[0].cls += ' fc-first';
11124 ret[4].cls += ' fc-prev-last';
11125 ret[5].cls += ' fc-last';
11132 cls: 'fc-border-separate',
11133 style : 'width:100%',
11141 cls : 'fc-first fc-last',
11159 cls : 'fc-content',
11160 style : "position: relative;",
11163 cls : 'fc-view fc-view-month fc-grid',
11164 style : 'position: relative',
11165 unselectable : 'on',
11168 cls : 'fc-event-container',
11169 style : 'position:absolute;z-index:8;top:0;left:0;'
11187 initEvents : function()
11190 throw "can not find store for calendar";
11196 style: "text-align:center",
11200 style: "background-color:white;width:50%;margin:250 auto",
11204 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
11215 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
11217 var size = this.el.select('.fc-content', true).first().getSize();
11218 this.maskEl.setSize(size.width, size.height);
11219 this.maskEl.enableDisplayMode("block");
11220 if(!this.loadMask){
11221 this.maskEl.hide();
11224 this.store = Roo.factory(this.store, Roo.data);
11225 this.store.on('load', this.onLoad, this);
11226 this.store.on('beforeload', this.onBeforeLoad, this);
11230 this.cells = this.el.select('.fc-day',true);
11231 //Roo.log(this.cells);
11232 this.textNodes = this.el.query('.fc-day-number');
11233 this.cells.addClassOnOver('fc-state-hover');
11235 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
11236 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
11237 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
11238 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
11240 this.on('monthchange', this.onMonthChange, this);
11242 this.update(new Date().clearTime());
11245 resize : function() {
11246 var sz = this.el.getSize();
11248 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
11249 this.el.select('.fc-day-content div',true).setHeight(34);
11254 showPrevMonth : function(e){
11255 this.update(this.activeDate.add("mo", -1));
11257 showToday : function(e){
11258 this.update(new Date().clearTime());
11261 showNextMonth : function(e){
11262 this.update(this.activeDate.add("mo", 1));
11266 showPrevYear : function(){
11267 this.update(this.activeDate.add("y", -1));
11271 showNextYear : function(){
11272 this.update(this.activeDate.add("y", 1));
11277 update : function(date)
11279 var vd = this.activeDate;
11280 this.activeDate = date;
11281 // if(vd && this.el){
11282 // var t = date.getTime();
11283 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
11284 // Roo.log('using add remove');
11286 // this.fireEvent('monthchange', this, date);
11288 // this.cells.removeClass("fc-state-highlight");
11289 // this.cells.each(function(c){
11290 // if(c.dateValue == t){
11291 // c.addClass("fc-state-highlight");
11292 // setTimeout(function(){
11293 // try{c.dom.firstChild.focus();}catch(e){}
11303 var days = date.getDaysInMonth();
11305 var firstOfMonth = date.getFirstDateOfMonth();
11306 var startingPos = firstOfMonth.getDay()-this.startDay;
11308 if(startingPos < this.startDay){
11312 var pm = date.add(Date.MONTH, -1);
11313 var prevStart = pm.getDaysInMonth()-startingPos;
11315 this.cells = this.el.select('.fc-day',true);
11316 this.textNodes = this.el.query('.fc-day-number');
11317 this.cells.addClassOnOver('fc-state-hover');
11319 var cells = this.cells.elements;
11320 var textEls = this.textNodes;
11322 Roo.each(cells, function(cell){
11323 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
11326 days += startingPos;
11328 // convert everything to numbers so it's fast
11329 var day = 86400000;
11330 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
11333 //Roo.log(prevStart);
11335 var today = new Date().clearTime().getTime();
11336 var sel = date.clearTime().getTime();
11337 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
11338 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
11339 var ddMatch = this.disabledDatesRE;
11340 var ddText = this.disabledDatesText;
11341 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
11342 var ddaysText = this.disabledDaysText;
11343 var format = this.format;
11345 var setCellClass = function(cal, cell){
11349 //Roo.log('set Cell Class');
11351 var t = d.getTime();
11355 cell.dateValue = t;
11357 cell.className += " fc-today";
11358 cell.className += " fc-state-highlight";
11359 cell.title = cal.todayText;
11362 // disable highlight in other month..
11363 //cell.className += " fc-state-highlight";
11368 cell.className = " fc-state-disabled";
11369 cell.title = cal.minText;
11373 cell.className = " fc-state-disabled";
11374 cell.title = cal.maxText;
11378 if(ddays.indexOf(d.getDay()) != -1){
11379 cell.title = ddaysText;
11380 cell.className = " fc-state-disabled";
11383 if(ddMatch && format){
11384 var fvalue = d.dateFormat(format);
11385 if(ddMatch.test(fvalue)){
11386 cell.title = ddText.replace("%0", fvalue);
11387 cell.className = " fc-state-disabled";
11391 if (!cell.initialClassName) {
11392 cell.initialClassName = cell.dom.className;
11395 cell.dom.className = cell.initialClassName + ' ' + cell.className;
11400 for(; i < startingPos; i++) {
11401 textEls[i].innerHTML = (++prevStart);
11402 d.setDate(d.getDate()+1);
11404 cells[i].className = "fc-past fc-other-month";
11405 setCellClass(this, cells[i]);
11410 for(; i < days; i++){
11411 intDay = i - startingPos + 1;
11412 textEls[i].innerHTML = (intDay);
11413 d.setDate(d.getDate()+1);
11415 cells[i].className = ''; // "x-date-active";
11416 setCellClass(this, cells[i]);
11420 for(; i < 42; i++) {
11421 textEls[i].innerHTML = (++extraDays);
11422 d.setDate(d.getDate()+1);
11424 cells[i].className = "fc-future fc-other-month";
11425 setCellClass(this, cells[i]);
11428 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
11430 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
11432 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
11433 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
11435 if(totalRows != 6){
11436 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
11437 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
11440 this.fireEvent('monthchange', this, date);
11444 if(!this.internalRender){
11445 var main = this.el.dom.firstChild;
11446 var w = main.offsetWidth;
11447 this.el.setWidth(w + this.el.getBorderWidth("lr"));
11448 Roo.fly(main).setWidth(w);
11449 this.internalRender = true;
11450 // opera does not respect the auto grow header center column
11451 // then, after it gets a width opera refuses to recalculate
11452 // without a second pass
11453 if(Roo.isOpera && !this.secondPass){
11454 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
11455 this.secondPass = true;
11456 this.update.defer(10, this, [date]);
11463 findCell : function(dt) {
11464 dt = dt.clearTime().getTime();
11466 this.cells.each(function(c){
11467 //Roo.log("check " +c.dateValue + '?=' + dt);
11468 if(c.dateValue == dt){
11478 findCells : function(ev) {
11479 var s = ev.start.clone().clearTime().getTime();
11481 var e= ev.end.clone().clearTime().getTime();
11484 this.cells.each(function(c){
11485 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
11487 if(c.dateValue > e){
11490 if(c.dateValue < s){
11499 // findBestRow: function(cells)
11503 // for (var i =0 ; i < cells.length;i++) {
11504 // ret = Math.max(cells[i].rows || 0,ret);
11511 addItem : function(ev)
11513 // look for vertical location slot in
11514 var cells = this.findCells(ev);
11516 // ev.row = this.findBestRow(cells);
11518 // work out the location.
11522 for(var i =0; i < cells.length; i++) {
11524 cells[i].row = cells[0].row;
11527 cells[i].row = cells[i].row + 1;
11537 if (crow.start.getY() == cells[i].getY()) {
11539 crow.end = cells[i];
11556 cells[0].events.push(ev);
11558 // if((typeof(cells[0].events) == 'undefined')){
11559 // cells[0].events = [];
11562 // cells[0].events.push(ev);
11563 // ev.rendered = false;
11564 // for (var i = 0; i < cells.length;i++) {
11565 // cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
11569 this.calevents.push(ev);
11572 clearEvents: function() {
11574 if(!this.calevents){
11578 Roo.each(this.cells.elements, function(c){
11584 Roo.each(this.calevents, function(e) {
11585 Roo.each(e.els, function(el) {
11586 el.un('mouseenter' ,this.onEventEnter, this);
11587 el.un('mouseleave' ,this.onEventLeave, this);
11592 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
11598 renderEvents: function()
11600 // for (var e = 0; e < this.calevents.length; e++) {
11602 // var ev = this.calevents[e];
11603 // var cells = ev.cells;
11604 // var rows = ev.rows;
11606 // for (var j = 0; j < cells.length; j++){
11608 // if(!cells[j].more.length){
11611 // if(cells[j].row > 3){
11612 // cells[j].more.push(ev);
11616 // cells[j].events.push(ev);
11620 // for (var i = 0; i < rows.length; i++){
11621 // // how many rows should it span..
11624 // cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
11625 // style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
11627 // unselectable : "on",
11630 // cls: 'fc-event-inner',
11634 //// cls: 'fc-event-time',
11635 //// html : cells.length > 1 ? '' : ev.time
11639 // cls: 'fc-event-title',
11640 // html : String.format('{0}', ev.title)
11647 // cls: 'ui-resizable-handle ui-resizable-e',
11648 // html : '  '
11655 // cfg.cls += ' fc-event-start';
11657 // if ((i+1) == rows.length) {
11658 // cfg.cls += ' fc-event-end';
11661 // var ctr = this.el.select('.fc-event-container',true).first();
11662 // var cg = ctr.createChild(cfg);
11664 // var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
11665 // var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
11667 // cg.setXY([sbox.x +2, sbox.y +(e * 20)]);
11668 // cg.setWidth(ebox.right - sbox.x -2);
11670 // cg.on('mouseenter' ,this.onEventEnter, this, ev);
11671 // cg.on('mouseleave' ,this.onEventLeave, this, ev);
11672 // cg.on('click', this.onEventClick, this, ev);
11674 // ev.els.push(cg);
11682 this.cells.each(function(c) {
11691 if(c.row != c.events.length){
11692 r = 4 - (4 - (c.row - c.events.length));
11695 c.events = ev.slice(0, r);
11696 c.more = ev.slice(r);
11698 if(c.more.length && c.more.length == 1){
11699 c.events.push(c.more.pop());
11702 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
11706 // for (var e = 0; e < this.calevents.length; e++) {
11708 // var ev = this.calevents[e];
11709 // var cells = ev.cells;
11710 // var rows = ev.rows;
11712 // for(var i = 0; i < cells.length; i++){
11714 // var cbox = this.cells.item(this.cells.indexOf(cells[i]));
11716 // if(cells.length < 2 && cbox.rows.length > 3){
11717 // cbox.more.push(ev);
11721 // cbox.rows.push(ev);
11725 this.cells.each(function(c) {
11727 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
11730 for (var e = 0; e < c.events.length; e++){
11731 var ev = c.events[e];
11732 var rows = ev.rows;
11734 for(var i = 0; i < rows.length; i++) {
11736 // how many rows should it span..
11739 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
11740 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
11742 unselectable : "on",
11745 cls: 'fc-event-inner',
11749 // cls: 'fc-event-time',
11750 // html : cells.length > 1 ? '' : ev.time
11754 cls: 'fc-event-title',
11755 html : String.format('{0}', ev.title)
11762 cls: 'ui-resizable-handle ui-resizable-e',
11763 html : '  '
11770 cfg.cls += ' fc-event-start';
11772 if ((i+1) == rows.length) {
11773 cfg.cls += ' fc-event-end';
11776 var ctr = _this.el.select('.fc-event-container',true).first();
11777 var cg = ctr.createChild(cfg);
11779 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
11780 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
11782 var r = (c.more.length) ? 1 : 0;
11783 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
11784 cg.setWidth(ebox.right - sbox.x -2);
11786 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
11787 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
11788 cg.on('click', _this.onEventClick, _this, ev);
11799 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
11800 style : 'position: absolute',
11801 unselectable : "on",
11804 cls: 'fc-event-inner',
11808 cls: 'fc-event-title',
11816 cls: 'ui-resizable-handle ui-resizable-e',
11817 html : '  '
11823 var ctr = _this.el.select('.fc-event-container',true).first();
11824 var cg = ctr.createChild(cfg);
11826 var sbox = c.select('.fc-day-content',true).first().getBox();
11827 var ebox = c.select('.fc-day-content',true).first().getBox();
11829 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
11830 cg.setWidth(ebox.right - sbox.x -2);
11832 cg.on('click', _this.onMoreEventClick, _this, c.more);
11842 onEventEnter: function (e, el,event,d) {
11843 this.fireEvent('evententer', this, el, event);
11846 onEventLeave: function (e, el,event,d) {
11847 this.fireEvent('eventleave', this, el, event);
11850 onEventClick: function (e, el,event,d) {
11851 this.fireEvent('eventclick', this, el, event);
11854 onMonthChange: function () {
11858 onMoreEventClick: function(e, el, more)
11862 this.calpopover.placement = 'right';
11863 this.calpopover.setTitle('More');
11865 this.calpopover.setContent('');
11867 var ctr = this.calpopover.el.select('.popover-content', true).first();
11869 Roo.each(more, function(m){
11871 cls : 'fc-event-hori fc-event-draggable',
11874 var cg = ctr.createChild(cfg);
11876 cg.on('click', _this.onEventClick, _this, m);
11879 this.calpopover.show(el);
11884 onLoad: function ()
11886 this.calevents = [];
11889 if(this.store.getCount() > 0){
11890 this.store.data.each(function(d){
11893 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
11894 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
11895 time : d.data.start_time,
11896 title : d.data.title,
11897 description : d.data.description,
11898 venue : d.data.venue
11903 this.renderEvents();
11905 if(this.calevents.length && this.loadMask){
11906 this.maskEl.hide();
11910 onBeforeLoad: function()
11912 this.clearEvents();
11914 this.maskEl.show();
11928 * @class Roo.bootstrap.Popover
11929 * @extends Roo.bootstrap.Component
11930 * Bootstrap Popover class
11931 * @cfg {String} html contents of the popover (or false to use children..)
11932 * @cfg {String} title of popover (or false to hide)
11933 * @cfg {String} placement how it is placed
11934 * @cfg {String} trigger click || hover (or false to trigger manually)
11935 * @cfg {String} over what (parent or false to trigger manually.)
11938 * Create a new Popover
11939 * @param {Object} config The config object
11942 Roo.bootstrap.Popover = function(config){
11943 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
11946 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
11948 title: 'Fill in a title',
11951 placement : 'right',
11952 trigger : 'hover', // hover
11956 can_build_overlaid : false,
11958 getChildContainer : function()
11960 return this.el.select('.popover-content',true).first();
11963 getAutoCreate : function(){
11964 Roo.log('make popover?');
11966 cls : 'popover roo-dynamic',
11967 style: 'display:block',
11973 cls : 'popover-inner',
11977 cls: 'popover-title',
11981 cls : 'popover-content',
11992 setTitle: function(str)
11994 this.el.select('.popover-title',true).first().dom.innerHTML = str;
11996 setContent: function(str)
11998 this.el.select('.popover-content',true).first().dom.innerHTML = str;
12000 // as it get's added to the bottom of the page.
12001 onRender : function(ct, position)
12003 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
12005 var cfg = Roo.apply({}, this.getAutoCreate());
12009 cfg.cls += ' ' + this.cls;
12012 cfg.style = this.style;
12014 Roo.log("adding to ")
12015 this.el = Roo.get(document.body).createChild(cfg, position);
12021 initEvents : function()
12023 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
12024 this.el.enableDisplayMode('block');
12026 if (this.over === false) {
12029 if (this.triggers === false) {
12032 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
12033 var triggers = this.trigger ? this.trigger.split(' ') : [];
12034 Roo.each(triggers, function(trigger) {
12036 if (trigger == 'click') {
12037 on_el.on('click', this.toggle, this);
12038 } else if (trigger != 'manual') {
12039 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
12040 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
12042 on_el.on(eventIn ,this.enter, this);
12043 on_el.on(eventOut, this.leave, this);
12054 toggle : function () {
12055 this.hoverState == 'in' ? this.leave() : this.enter();
12058 enter : function () {
12061 clearTimeout(this.timeout);
12063 this.hoverState = 'in'
12065 if (!this.delay || !this.delay.show) {
12070 this.timeout = setTimeout(function () {
12071 if (_t.hoverState == 'in') {
12074 }, this.delay.show)
12076 leave : function() {
12077 clearTimeout(this.timeout);
12079 this.hoverState = 'out'
12081 if (!this.delay || !this.delay.hide) {
12086 this.timeout = setTimeout(function () {
12087 if (_t.hoverState == 'out') {
12090 }, this.delay.hide)
12093 show : function (on_el)
12096 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
12099 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
12100 if (this.html !== false) {
12101 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
12103 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
12104 if (!this.title.length) {
12105 this.el.select('.popover-title',true).hide();
12108 var placement = typeof this.placement == 'function' ?
12109 this.placement.call(this, this.el, on_el) :
12112 var autoToken = /\s?auto?\s?/i;
12113 var autoPlace = autoToken.test(placement);
12115 placement = placement.replace(autoToken, '') || 'top';
12119 //this.el.setXY([0,0]);
12121 this.el.dom.style.display='block';
12122 this.el.addClass(placement);
12124 //this.el.appendTo(on_el);
12126 var p = this.getPosition();
12127 var box = this.el.getBox();
12132 var align = Roo.bootstrap.Popover.alignment[placement]
12133 this.el.alignTo(on_el, align[0],align[1]);
12134 //var arrow = this.el.select('.arrow',true).first();
12135 //arrow.set(align[2],
12137 this.el.addClass('in');
12138 this.hoverState = null;
12140 if (this.el.hasClass('fade')) {
12147 this.el.setXY([0,0]);
12148 this.el.removeClass('in');
12155 Roo.bootstrap.Popover.alignment = {
12156 'left' : ['r-l', [-10,0], 'right'],
12157 'right' : ['l-r', [10,0], 'left'],
12158 'bottom' : ['t-b', [0,10], 'top'],
12159 'top' : [ 'b-t', [0,-10], 'bottom']
12170 * @class Roo.bootstrap.Progress
12171 * @extends Roo.bootstrap.Component
12172 * Bootstrap Progress class
12173 * @cfg {Boolean} striped striped of the progress bar
12174 * @cfg {Boolean} active animated of the progress bar
12178 * Create a new Progress
12179 * @param {Object} config The config object
12182 Roo.bootstrap.Progress = function(config){
12183 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
12186 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
12191 getAutoCreate : function(){
12199 cfg.cls += ' progress-striped';
12203 cfg.cls += ' active';
12222 * @class Roo.bootstrap.ProgressBar
12223 * @extends Roo.bootstrap.Component
12224 * Bootstrap ProgressBar class
12225 * @cfg {Number} aria_valuenow aria-value now
12226 * @cfg {Number} aria_valuemin aria-value min
12227 * @cfg {Number} aria_valuemax aria-value max
12228 * @cfg {String} label label for the progress bar
12229 * @cfg {String} panel (success | info | warning | danger )
12230 * @cfg {String} role role of the progress bar
12231 * @cfg {String} sr_only text
12235 * Create a new ProgressBar
12236 * @param {Object} config The config object
12239 Roo.bootstrap.ProgressBar = function(config){
12240 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
12243 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
12247 aria_valuemax : 100,
12253 getAutoCreate : function()
12258 cls: 'progress-bar',
12259 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
12271 cfg.role = this.role;
12274 if(this.aria_valuenow){
12275 cfg['aria-valuenow'] = this.aria_valuenow;
12278 if(this.aria_valuemin){
12279 cfg['aria-valuemin'] = this.aria_valuemin;
12282 if(this.aria_valuemax){
12283 cfg['aria-valuemax'] = this.aria_valuemax;
12286 if(this.label && !this.sr_only){
12287 cfg.html = this.label;
12291 cfg.cls += ' progress-bar-' + this.panel;
12297 update : function(aria_valuenow)
12299 this.aria_valuenow = aria_valuenow;
12301 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
12316 * @class Roo.bootstrap.TabPanel
12317 * @extends Roo.bootstrap.Component
12318 * Bootstrap TabPanel class
12319 * @cfg {Boolean} active panel active
12320 * @cfg {String} html panel content
12321 * @cfg {String} tabId tab relate id
12322 * @cfg {String} navId The navbar which triggers show hide
12326 * Create a new TabPanel
12327 * @param {Object} config The config object
12330 Roo.bootstrap.TabPanel = function(config){
12331 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
12335 * Fires when the active status changes
12336 * @param {Roo.bootstrap.TabPanel} this
12337 * @param {Boolean} state the new state
12344 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
12351 getAutoCreate : function(){
12355 html: this.html || ''
12359 cfg.cls += ' active';
12363 cfg.tabId = this.tabId;
12368 onRender : function(ct, position)
12370 // Roo.log("Call onRender: " + this.xtype);
12372 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
12374 if (this.navId && this.tabId) {
12375 var item = Roo.bootstrap.NavGroup.get(this.navId).getNavItem(this.tabId);
12377 Roo.log("could not find navID:" + this.navId + ", tabId: " + this.tabId);
12379 item.on('changed', function(item, state) {
12380 this.setActive(state);
12386 setActive: function(state)
12388 Roo.log("panel - set active " + this.tabId + "=" + state);
12390 this.active = state;
12392 this.el.removeClass('active');
12394 } else if (!this.el.hasClass('active')) {
12395 this.el.addClass('active');
12397 this.fireEvent('changed', this, state);
12414 * @class Roo.bootstrap.DateField
12415 * @extends Roo.bootstrap.Input
12416 * Bootstrap DateField class
12417 * @cfg {Number} weekStart default 0
12418 * @cfg {Number} weekStart default 0
12419 * @cfg {Number} viewMode default empty, (months|years)
12420 * @cfg {Number} minViewMode default empty, (months|years)
12421 * @cfg {Number} startDate default -Infinity
12422 * @cfg {Number} endDate default Infinity
12423 * @cfg {Boolean} todayHighlight default false
12424 * @cfg {Boolean} todayBtn default false
12425 * @cfg {Boolean} calendarWeeks default false
12426 * @cfg {Object} daysOfWeekDisabled default empty
12428 * @cfg {Boolean} keyboardNavigation default true
12429 * @cfg {String} language default en
12432 * Create a new DateField
12433 * @param {Object} config The config object
12436 Roo.bootstrap.DateField = function(config){
12437 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
12441 * Fires when this field show.
12442 * @param {Roo.bootstrap.DateField} this
12443 * @param {Mixed} date The date value
12448 * Fires when this field hide.
12449 * @param {Roo.bootstrap.DateField} this
12450 * @param {Mixed} date The date value
12455 * Fires when select a date.
12456 * @param {Roo.bootstrap.DateField} this
12457 * @param {Mixed} date The date value
12463 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
12466 * @cfg {String} format
12467 * The default date format string which can be overriden for localization support. The format must be
12468 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
12472 * @cfg {String} altFormats
12473 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
12474 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
12476 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
12484 todayHighlight : false,
12490 keyboardNavigation: true,
12492 calendarWeeks: false,
12494 startDate: -Infinity,
12498 daysOfWeekDisabled: [],
12502 UTCDate: function()
12504 return new Date(Date.UTC.apply(Date, arguments));
12507 UTCToday: function()
12509 var today = new Date();
12510 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
12513 getDate: function() {
12514 var d = this.getUTCDate();
12515 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
12518 getUTCDate: function() {
12522 setDate: function(d) {
12523 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
12526 setUTCDate: function(d) {
12528 this.setValue(this.formatDate(this.date));
12531 onRender: function(ct, position)
12534 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
12536 this.language = this.language || 'en';
12537 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
12538 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
12540 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
12541 this.format = this.format || 'm/d/y';
12542 this.isInline = false;
12543 this.isInput = true;
12544 this.component = this.el.select('.add-on', true).first() || false;
12545 this.component = (this.component && this.component.length === 0) ? false : this.component;
12546 this.hasInput = this.component && this.inputEL().length;
12548 if (typeof(this.minViewMode === 'string')) {
12549 switch (this.minViewMode) {
12551 this.minViewMode = 1;
12554 this.minViewMode = 2;
12557 this.minViewMode = 0;
12562 if (typeof(this.viewMode === 'string')) {
12563 switch (this.viewMode) {
12576 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
12578 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12580 this.picker().on('mousedown', this.onMousedown, this);
12581 this.picker().on('click', this.onClick, this);
12583 this.picker().addClass('datepicker-dropdown');
12585 this.startViewMode = this.viewMode;
12588 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
12589 if(!this.calendarWeeks){
12594 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
12595 v.attr('colspan', function(i, val){
12596 return parseInt(val) + 1;
12601 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
12603 this.setStartDate(this.startDate);
12604 this.setEndDate(this.endDate);
12606 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
12613 if(this.isInline) {
12618 picker : function()
12620 return this.el.select('.datepicker', true).first();
12623 fillDow: function()
12625 var dowCnt = this.weekStart;
12634 if(this.calendarWeeks){
12642 while (dowCnt < this.weekStart + 7) {
12646 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
12650 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
12653 fillMonths: function()
12656 var months = this.picker().select('>.datepicker-months td', true).first();
12658 months.dom.innerHTML = '';
12664 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
12667 months.createChild(month);
12672 update: function(){
12674 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
12676 if (this.date < this.startDate) {
12677 this.viewDate = new Date(this.startDate);
12678 } else if (this.date > this.endDate) {
12679 this.viewDate = new Date(this.endDate);
12681 this.viewDate = new Date(this.date);
12688 var d = new Date(this.viewDate),
12689 year = d.getUTCFullYear(),
12690 month = d.getUTCMonth(),
12691 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
12692 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
12693 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
12694 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
12695 currentDate = this.date && this.date.valueOf(),
12696 today = this.UTCToday();
12698 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
12700 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
12702 // this.picker.select('>tfoot th.today').
12703 // .text(dates[this.language].today)
12704 // .toggle(this.todayBtn !== false);
12706 this.updateNavArrows();
12709 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
12711 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
12713 prevMonth.setUTCDate(day);
12715 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
12717 var nextMonth = new Date(prevMonth);
12719 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
12721 nextMonth = nextMonth.valueOf();
12723 var fillMonths = false;
12725 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
12727 while(prevMonth.valueOf() < nextMonth) {
12730 if (prevMonth.getUTCDay() === this.weekStart) {
12732 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
12740 if(this.calendarWeeks){
12741 // ISO 8601: First week contains first thursday.
12742 // ISO also states week starts on Monday, but we can be more abstract here.
12744 // Start of current week: based on weekstart/current date
12745 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
12746 // Thursday of this week
12747 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
12748 // First Thursday of year, year from thursday
12749 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
12750 // Calendar week: ms between thursdays, div ms per day, div 7 days
12751 calWeek = (th - yth) / 864e5 / 7 + 1;
12753 fillMonths.cn.push({
12761 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
12763 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
12766 if (this.todayHighlight &&
12767 prevMonth.getUTCFullYear() == today.getFullYear() &&
12768 prevMonth.getUTCMonth() == today.getMonth() &&
12769 prevMonth.getUTCDate() == today.getDate()) {
12770 clsName += ' today';
12773 if (currentDate && prevMonth.valueOf() === currentDate) {
12774 clsName += ' active';
12777 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
12778 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
12779 clsName += ' disabled';
12782 fillMonths.cn.push({
12784 cls: 'day ' + clsName,
12785 html: prevMonth.getDate()
12788 prevMonth.setDate(prevMonth.getDate()+1);
12791 var currentYear = this.date && this.date.getUTCFullYear();
12792 var currentMonth = this.date && this.date.getUTCMonth();
12794 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
12796 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
12797 v.removeClass('active');
12799 if(currentYear === year && k === currentMonth){
12800 v.addClass('active');
12803 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
12804 v.addClass('disabled');
12810 year = parseInt(year/10, 10) * 10;
12812 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
12814 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
12817 for (var i = -1; i < 11; i++) {
12818 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
12820 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
12828 showMode: function(dir) {
12830 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
12832 Roo.each(this.picker().select('>div',true).elements, function(v){
12833 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12836 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
12841 if(this.isInline) return;
12843 this.picker().removeClass(['bottom', 'top']);
12845 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
12847 * place to the top of element!
12851 this.picker().addClass('top');
12852 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12857 this.picker().addClass('bottom');
12859 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12862 parseDate : function(value){
12863 if(!value || value instanceof Date){
12866 var v = Date.parseDate(value, this.format);
12867 if (!v && this.useIso) {
12868 v = Date.parseDate(value, 'Y-m-d');
12870 if(!v && this.altFormats){
12871 if(!this.altFormatsArray){
12872 this.altFormatsArray = this.altFormats.split("|");
12874 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
12875 v = Date.parseDate(value, this.altFormatsArray[i]);
12881 formatDate : function(date, fmt){
12882 return (!date || !(date instanceof Date)) ?
12883 date : date.dateFormat(fmt || this.format);
12886 onFocus : function()
12888 Roo.bootstrap.DateField.superclass.onFocus.call(this);
12892 onBlur : function()
12894 Roo.bootstrap.DateField.superclass.onBlur.call(this);
12900 this.picker().show();
12904 this.fireEvent('show', this, this.date);
12909 if(this.isInline) return;
12910 this.picker().hide();
12911 this.viewMode = this.startViewMode;
12914 this.fireEvent('hide', this, this.date);
12918 onMousedown: function(e){
12919 e.stopPropagation();
12920 e.preventDefault();
12923 keyup: function(e){
12924 Roo.bootstrap.DateField.superclass.keyup.call(this);
12929 setValue: function(v){
12930 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
12932 this.fireEvent('select', this, this.date);
12936 fireKey: function(e){
12937 if (!this.picker().isVisible()){
12938 if (e.keyCode == 27) // allow escape to hide and re-show picker
12942 var dateChanged = false,
12944 newDate, newViewDate;
12948 e.preventDefault();
12952 if (!this.keyboardNavigation) break;
12953 dir = e.keyCode == 37 ? -1 : 1;
12956 newDate = this.moveYear(this.date, dir);
12957 newViewDate = this.moveYear(this.viewDate, dir);
12958 } else if (e.shiftKey){
12959 newDate = this.moveMonth(this.date, dir);
12960 newViewDate = this.moveMonth(this.viewDate, dir);
12962 newDate = new Date(this.date);
12963 newDate.setUTCDate(this.date.getUTCDate() + dir);
12964 newViewDate = new Date(this.viewDate);
12965 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
12967 if (this.dateWithinRange(newDate)){
12968 this.date = newDate;
12969 this.viewDate = newViewDate;
12970 this.setValue(this.formatDate(this.date));
12972 e.preventDefault();
12973 dateChanged = true;
12978 if (!this.keyboardNavigation) break;
12979 dir = e.keyCode == 38 ? -1 : 1;
12981 newDate = this.moveYear(this.date, dir);
12982 newViewDate = this.moveYear(this.viewDate, dir);
12983 } else if (e.shiftKey){
12984 newDate = this.moveMonth(this.date, dir);
12985 newViewDate = this.moveMonth(this.viewDate, dir);
12987 newDate = new Date(this.date);
12988 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
12989 newViewDate = new Date(this.viewDate);
12990 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
12992 if (this.dateWithinRange(newDate)){
12993 this.date = newDate;
12994 this.viewDate = newViewDate;
12995 this.setValue(this.formatDate(this.date));
12997 e.preventDefault();
12998 dateChanged = true;
13002 this.setValue(this.formatDate(this.date));
13004 e.preventDefault();
13007 this.setValue(this.formatDate(this.date));
13014 onClick: function(e) {
13015 e.stopPropagation();
13016 e.preventDefault();
13018 var target = e.getTarget();
13020 if(target.nodeName.toLowerCase() === 'i'){
13021 target = Roo.get(target).dom.parentNode;
13024 var nodeName = target.nodeName;
13025 var className = target.className;
13026 var html = target.innerHTML;
13028 switch(nodeName.toLowerCase()) {
13030 switch(className) {
13036 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
13037 switch(this.viewMode){
13039 this.viewDate = this.moveMonth(this.viewDate, dir);
13043 this.viewDate = this.moveYear(this.viewDate, dir);
13049 var date = new Date();
13050 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
13052 this.setValue(this.formatDate(this.date));
13058 if (className.indexOf('disabled') === -1) {
13059 this.viewDate.setUTCDate(1);
13060 if (className.indexOf('month') !== -1) {
13061 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
13063 var year = parseInt(html, 10) || 0;
13064 this.viewDate.setUTCFullYear(year);
13073 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
13074 var day = parseInt(html, 10) || 1;
13075 var year = this.viewDate.getUTCFullYear(),
13076 month = this.viewDate.getUTCMonth();
13078 if (className.indexOf('old') !== -1) {
13085 } else if (className.indexOf('new') !== -1) {
13093 this.date = this.UTCDate(year, month, day,0,0,0,0);
13094 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
13096 this.setValue(this.formatDate(this.date));
13103 setStartDate: function(startDate){
13104 this.startDate = startDate || -Infinity;
13105 if (this.startDate !== -Infinity) {
13106 this.startDate = this.parseDate(this.startDate);
13109 this.updateNavArrows();
13112 setEndDate: function(endDate){
13113 this.endDate = endDate || Infinity;
13114 if (this.endDate !== Infinity) {
13115 this.endDate = this.parseDate(this.endDate);
13118 this.updateNavArrows();
13121 setDaysOfWeekDisabled: function(daysOfWeekDisabled){
13122 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
13123 if (typeof(this.daysOfWeekDisabled) !== 'object') {
13124 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
13126 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
13127 return parseInt(d, 10);
13130 this.updateNavArrows();
13133 updateNavArrows: function() {
13134 var d = new Date(this.viewDate),
13135 year = d.getUTCFullYear(),
13136 month = d.getUTCMonth();
13138 Roo.each(this.picker().select('.prev', true).elements, function(v){
13140 switch (this.viewMode) {
13143 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
13149 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
13156 Roo.each(this.picker().select('.next', true).elements, function(v){
13158 switch (this.viewMode) {
13161 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
13167 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
13175 moveMonth: function(date, dir){
13176 if (!dir) return date;
13177 var new_date = new Date(date.valueOf()),
13178 day = new_date.getUTCDate(),
13179 month = new_date.getUTCMonth(),
13180 mag = Math.abs(dir),
13182 dir = dir > 0 ? 1 : -1;
13185 // If going back one month, make sure month is not current month
13186 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
13188 return new_date.getUTCMonth() == month;
13190 // If going forward one month, make sure month is as expected
13191 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
13193 return new_date.getUTCMonth() != new_month;
13195 new_month = month + dir;
13196 new_date.setUTCMonth(new_month);
13197 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
13198 if (new_month < 0 || new_month > 11)
13199 new_month = (new_month + 12) % 12;
13201 // For magnitudes >1, move one month at a time...
13202 for (var i=0; i<mag; i++)
13203 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
13204 new_date = this.moveMonth(new_date, dir);
13205 // ...then reset the day, keeping it in the new month
13206 new_month = new_date.getUTCMonth();
13207 new_date.setUTCDate(day);
13209 return new_month != new_date.getUTCMonth();
13212 // Common date-resetting loop -- if date is beyond end of month, make it
13215 new_date.setUTCDate(--day);
13216 new_date.setUTCMonth(new_month);
13221 moveYear: function(date, dir){
13222 return this.moveMonth(date, dir*12);
13225 dateWithinRange: function(date){
13226 return date >= this.startDate && date <= this.endDate;
13230 remove: function() {
13231 this.picker().remove();
13236 Roo.apply(Roo.bootstrap.DateField, {
13247 html: '<i class="icon-arrow-left"/>'
13257 html: '<i class="icon-arrow-right"/>'
13299 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
13300 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
13301 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
13302 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
13303 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
13316 navFnc: 'FullYear',
13321 navFnc: 'FullYear',
13326 Roo.apply(Roo.bootstrap.DateField, {
13330 cls: 'datepicker dropdown-menu',
13334 cls: 'datepicker-days',
13338 cls: 'table-condensed',
13340 Roo.bootstrap.DateField.head,
13344 Roo.bootstrap.DateField.footer
13351 cls: 'datepicker-months',
13355 cls: 'table-condensed',
13357 Roo.bootstrap.DateField.head,
13358 Roo.bootstrap.DateField.content,
13359 Roo.bootstrap.DateField.footer
13366 cls: 'datepicker-years',
13370 cls: 'table-condensed',
13372 Roo.bootstrap.DateField.head,
13373 Roo.bootstrap.DateField.content,
13374 Roo.bootstrap.DateField.footer
13393 * @class Roo.bootstrap.TimeField
13394 * @extends Roo.bootstrap.Input
13395 * Bootstrap DateField class
13399 * Create a new TimeField
13400 * @param {Object} config The config object
13403 Roo.bootstrap.TimeField = function(config){
13404 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
13408 * Fires when this field show.
13409 * @param {Roo.bootstrap.DateField} this
13410 * @param {Mixed} date The date value
13415 * Fires when this field hide.
13416 * @param {Roo.bootstrap.DateField} this
13417 * @param {Mixed} date The date value
13422 * Fires when select a date.
13423 * @param {Roo.bootstrap.DateField} this
13424 * @param {Mixed} date The date value
13430 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
13433 * @cfg {String} format
13434 * The default time format string which can be overriden for localization support. The format must be
13435 * valid according to {@link Date#parseDate} (defaults to 'H:i').
13439 onRender: function(ct, position)
13442 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
13444 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
13446 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13448 this.pop = this.picker().select('>.datepicker-time',true).first();
13449 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
13451 this.picker().on('mousedown', this.onMousedown, this);
13452 this.picker().on('click', this.onClick, this);
13454 this.picker().addClass('datepicker-dropdown');
13459 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
13460 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
13461 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
13462 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
13463 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
13464 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
13468 fireKey: function(e){
13469 if (!this.picker().isVisible()){
13470 if (e.keyCode == 27) // allow escape to hide and re-show picker
13475 e.preventDefault();
13483 this.onTogglePeriod();
13486 this.onIncrementMinutes();
13489 this.onDecrementMinutes();
13498 onClick: function(e) {
13499 e.stopPropagation();
13500 e.preventDefault();
13503 picker : function()
13505 return this.el.select('.datepicker', true).first();
13508 fillTime: function()
13510 var time = this.pop.select('tbody', true).first();
13512 time.dom.innerHTML = '';
13527 cls: 'hours-up glyphicon glyphicon-chevron-up'
13547 cls: 'minutes-up glyphicon glyphicon-chevron-up'
13568 cls: 'timepicker-hour',
13583 cls: 'timepicker-minute',
13598 cls: 'btn btn-primary period',
13620 cls: 'hours-down glyphicon glyphicon-chevron-down'
13640 cls: 'minutes-down glyphicon glyphicon-chevron-down'
13658 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
13665 var hours = this.time.getHours();
13666 var minutes = this.time.getMinutes();
13679 hours = hours - 12;
13683 hours = '0' + hours;
13687 minutes = '0' + minutes;
13690 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
13691 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
13692 this.pop.select('button', true).first().dom.innerHTML = period;
13698 this.picker().removeClass(['bottom', 'top']);
13700 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
13702 * place to the top of element!
13706 this.picker().addClass('top');
13707 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13712 this.picker().addClass('bottom');
13714 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13717 onFocus : function()
13719 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
13723 onBlur : function()
13725 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
13731 this.picker().show();
13736 this.fireEvent('show', this, this.date);
13741 this.picker().hide();
13744 this.fireEvent('hide', this, this.date);
13747 setTime : function()
13750 this.setValue(this.time.format(this.format));
13752 this.fireEvent('select', this, this.date);
13757 onMousedown: function(e){
13758 e.stopPropagation();
13759 e.preventDefault();
13762 onIncrementHours: function()
13764 Roo.log('onIncrementHours');
13765 this.time = this.time.add(Date.HOUR, 1);
13770 onDecrementHours: function()
13772 Roo.log('onDecrementHours');
13773 this.time = this.time.add(Date.HOUR, -1);
13777 onIncrementMinutes: function()
13779 Roo.log('onIncrementMinutes');
13780 this.time = this.time.add(Date.MINUTE, 1);
13784 onDecrementMinutes: function()
13786 Roo.log('onDecrementMinutes');
13787 this.time = this.time.add(Date.MINUTE, -1);
13791 onTogglePeriod: function()
13793 Roo.log('onTogglePeriod');
13794 this.time = this.time.add(Date.HOUR, 12);
13801 Roo.apply(Roo.bootstrap.TimeField, {
13831 cls: 'btn btn-info ok',
13843 Roo.apply(Roo.bootstrap.TimeField, {
13847 cls: 'datepicker dropdown-menu',
13851 cls: 'datepicker-time',
13855 cls: 'table-condensed',
13857 Roo.bootstrap.TimeField.content,
13858 Roo.bootstrap.TimeField.footer
13877 * @class Roo.bootstrap.CheckBox
13878 * @extends Roo.bootstrap.Input
13879 * Bootstrap CheckBox class
13881 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
13882 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
13883 * @cfg {String} boxLabel The text that appears beside the checkbox
13884 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
13885 * @cfg {Boolean} checked initnal the element
13889 * Create a new CheckBox
13890 * @param {Object} config The config object
13893 Roo.bootstrap.CheckBox = function(config){
13894 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
13899 * Fires when the element is checked or unchecked.
13900 * @param {Roo.bootstrap.CheckBox} this This input
13901 * @param {Boolean} checked The new checked value
13907 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
13909 inputType: 'checkbox',
13916 getAutoCreate : function()
13918 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
13924 cfg.cls = 'form-group checkbox' //input-group
13932 type : this.inputType,
13933 value : (!this.checked) ? this.valueOff : this.inputValue,
13934 cls : 'roo-checkbox', //'form-box',
13935 placeholder : this.placeholder || ''
13939 if (this.weight) { // Validity check?
13940 cfg.cls += " checkbox-" + this.weight;
13943 if (this.disabled) {
13944 input.disabled=true;
13948 input.checked = this.checked;
13952 input.name = this.name;
13956 input.cls += ' input-' + this.size;
13960 ['xs','sm','md','lg'].map(function(size){
13961 if (settings[size]) {
13962 cfg.cls += ' col-' + size + '-' + settings[size];
13968 var inputblock = input;
13973 if (this.before || this.after) {
13976 cls : 'input-group',
13980 inputblock.cn.push({
13982 cls : 'input-group-addon',
13986 inputblock.cn.push(input);
13988 inputblock.cn.push({
13990 cls : 'input-group-addon',
13997 if (align ==='left' && this.fieldLabel.length) {
13998 Roo.log("left and has label");
14004 cls : 'control-label col-md-' + this.labelWidth,
14005 html : this.fieldLabel
14009 cls : "col-md-" + (12 - this.labelWidth),
14016 } else if ( this.fieldLabel.length) {
14021 tag: this.boxLabel ? 'span' : 'label',
14023 cls: 'control-label box-input-label',
14024 //cls : 'input-group-addon',
14025 html : this.fieldLabel
14035 Roo.log(" no label && no align");
14036 cfg.cn = [ inputblock ] ;
14045 html: this.boxLabel
14057 * return the real input element.
14059 inputEl: function ()
14061 return this.el.select('input.roo-checkbox',true).first();
14066 return this.el.select('label.control-label',true).first();
14069 initEvents : function()
14071 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
14073 this.inputEl().on('click', this.onClick, this);
14077 onClick : function()
14079 this.setChecked(!this.checked);
14082 setChecked : function(state,suppressEvent)
14084 this.checked = state;
14086 this.inputEl().dom.checked = state;
14088 if(suppressEvent !== true){
14089 this.fireEvent('check', this, state);
14092 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
14096 setValue : function(v,suppressEvent)
14098 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
14112 * @class Roo.bootstrap.Radio
14113 * @extends Roo.bootstrap.CheckBox
14114 * Bootstrap Radio class
14117 * Create a new Radio
14118 * @param {Object} config The config object
14121 Roo.bootstrap.Radio = function(config){
14122 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
14126 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
14128 inputType: 'radio',
14132 getAutoCreate : function()
14134 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
14140 cfg.cls = 'form-group radio' //input-group
14145 type : this.inputType,
14146 value : (!this.checked) ? this.valueOff : this.inputValue,
14148 placeholder : this.placeholder || ''
14151 if (this.weight) { // Validity check?
14152 cfg.cls += " radio-" + this.weight;
14154 if (this.disabled) {
14155 input.disabled=true;
14159 input.checked = this.checked;
14163 input.name = this.name;
14167 input.cls += ' input-' + this.size;
14171 ['xs','sm','md','lg'].map(function(size){
14172 if (settings[size]) {
14173 cfg.cls += ' col-' + size + '-' + settings[size];
14177 var inputblock = input;
14179 if (this.before || this.after) {
14182 cls : 'input-group',
14186 inputblock.cn.push({
14188 cls : 'input-group-addon',
14192 inputblock.cn.push(input);
14194 inputblock.cn.push({
14196 cls : 'input-group-addon',
14203 if (align ==='left' && this.fieldLabel.length) {
14204 Roo.log("left and has label");
14210 cls : 'control-label col-md-' + this.labelWidth,
14211 html : this.fieldLabel
14215 cls : "col-md-" + (12 - this.labelWidth),
14222 } else if ( this.fieldLabel.length) {
14229 cls: 'control-label box-input-label',
14230 //cls : 'input-group-addon',
14231 html : this.fieldLabel
14241 Roo.log(" no label && no align");
14256 html: this.boxLabel
14263 inputEl: function ()
14265 return this.el.select('input.roo-radio',true).first();
14267 onClick : function()
14269 this.setChecked(true);
14272 setChecked : function(state,suppressEvent)
14275 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
14276 v.dom.checked = false;
14280 this.checked = state;
14281 this.inputEl().dom.checked = state;
14283 if(suppressEvent !== true){
14284 this.fireEvent('check', this, state);
14287 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
14291 getGroupValue : function()
14294 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
14295 if(v.dom.checked == true){
14296 value = v.dom.value;
14304 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
14305 * @return {Mixed} value The field value
14307 getValue : function(){
14308 return this.getGroupValue();
14314 //<script type="text/javascript">
14317 * Based Ext JS Library 1.1.1
14318 * Copyright(c) 2006-2007, Ext JS, LLC.
14324 * @class Roo.HtmlEditorCore
14325 * @extends Roo.Component
14326 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
14328 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
14331 Roo.HtmlEditorCore = function(config){
14334 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
14337 * @event initialize
14338 * Fires when the editor is fully initialized (including the iframe)
14339 * @param {Roo.HtmlEditorCore} this
14344 * Fires when the editor is first receives the focus. Any insertion must wait
14345 * until after this event.
14346 * @param {Roo.HtmlEditorCore} this
14350 * @event beforesync
14351 * Fires before the textarea is updated with content from the editor iframe. Return false
14352 * to cancel the sync.
14353 * @param {Roo.HtmlEditorCore} this
14354 * @param {String} html
14358 * @event beforepush
14359 * Fires before the iframe editor is updated with content from the textarea. Return false
14360 * to cancel the push.
14361 * @param {Roo.HtmlEditorCore} this
14362 * @param {String} html
14367 * Fires when the textarea is updated with content from the editor iframe.
14368 * @param {Roo.HtmlEditorCore} this
14369 * @param {String} html
14374 * Fires when the iframe editor is updated with content from the textarea.
14375 * @param {Roo.HtmlEditorCore} this
14376 * @param {String} html
14381 * @event editorevent
14382 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
14383 * @param {Roo.HtmlEditorCore} this
14391 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
14395 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
14401 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
14406 * @cfg {Number} height (in pixels)
14410 * @cfg {Number} width (in pixels)
14415 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
14418 stylesheets: false,
14423 // private properties
14424 validationEvent : false,
14426 initialized : false,
14428 sourceEditMode : false,
14429 onFocus : Roo.emptyFn,
14431 hideMode:'offsets',
14439 * Protected method that will not generally be called directly. It
14440 * is called when the editor initializes the iframe with HTML contents. Override this method if you
14441 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
14443 getDocMarkup : function(){
14446 Roo.log(this.stylesheets);
14448 // inherit styels from page...??
14449 if (this.stylesheets === false) {
14451 Roo.get(document.head).select('style').each(function(node) {
14452 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
14455 Roo.get(document.head).select('link').each(function(node) {
14456 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
14459 } else if (!this.stylesheets.length) {
14461 st = '<style type="text/css">' +
14462 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
14465 Roo.each(this.stylesheets, function(s) {
14466 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
14471 st += '<style type="text/css">' +
14472 'IMG { cursor: pointer } ' +
14476 return '<html><head>' + st +
14477 //<style type="text/css">' +
14478 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
14480 ' </head><body class="roo-htmleditor-body"></body></html>';
14484 onRender : function(ct, position)
14487 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
14488 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
14491 this.el.dom.style.border = '0 none';
14492 this.el.dom.setAttribute('tabIndex', -1);
14493 this.el.addClass('x-hidden hide');
14497 if(Roo.isIE){ // fix IE 1px bogus margin
14498 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
14502 this.frameId = Roo.id();
14506 var iframe = this.owner.wrap.createChild({
14508 cls: 'form-control', // bootstrap..
14510 name: this.frameId,
14511 frameBorder : 'no',
14512 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
14517 this.iframe = iframe.dom;
14519 this.assignDocWin();
14521 this.doc.designMode = 'on';
14524 this.doc.write(this.getDocMarkup());
14528 var task = { // must defer to wait for browser to be ready
14530 //console.log("run task?" + this.doc.readyState);
14531 this.assignDocWin();
14532 if(this.doc.body || this.doc.readyState == 'complete'){
14534 this.doc.designMode="on";
14538 Roo.TaskMgr.stop(task);
14539 this.initEditor.defer(10, this);
14546 Roo.TaskMgr.start(task);
14553 onResize : function(w, h)
14555 Roo.log('resize: ' +w + ',' + h );
14556 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
14560 if(typeof w == 'number'){
14562 this.iframe.style.width = w + 'px';
14564 if(typeof h == 'number'){
14566 this.iframe.style.height = h + 'px';
14568 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
14575 * Toggles the editor between standard and source edit mode.
14576 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
14578 toggleSourceEdit : function(sourceEditMode){
14580 this.sourceEditMode = sourceEditMode === true;
14582 if(this.sourceEditMode){
14584 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
14587 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
14588 //this.iframe.className = '';
14591 //this.setSize(this.owner.wrap.getSize());
14592 //this.fireEvent('editmodechange', this, this.sourceEditMode);
14599 * Protected method that will not generally be called directly. If you need/want
14600 * custom HTML cleanup, this is the method you should override.
14601 * @param {String} html The HTML to be cleaned
14602 * return {String} The cleaned HTML
14604 cleanHtml : function(html){
14605 html = String(html);
14606 if(html.length > 5){
14607 if(Roo.isSafari){ // strip safari nonsense
14608 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
14611 if(html == ' '){
14618 * HTML Editor -> Textarea
14619 * Protected method that will not generally be called directly. Syncs the contents
14620 * of the editor iframe with the textarea.
14622 syncValue : function(){
14623 if(this.initialized){
14624 var bd = (this.doc.body || this.doc.documentElement);
14625 //this.cleanUpPaste(); -- this is done else where and causes havoc..
14626 var html = bd.innerHTML;
14628 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
14629 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
14631 html = '<div style="'+m[0]+'">' + html + '</div>';
14634 html = this.cleanHtml(html);
14635 // fix up the special chars.. normaly like back quotes in word...
14636 // however we do not want to do this with chinese..
14637 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
14638 var cc = b.charCodeAt();
14640 (cc >= 0x4E00 && cc < 0xA000 ) ||
14641 (cc >= 0x3400 && cc < 0x4E00 ) ||
14642 (cc >= 0xf900 && cc < 0xfb00 )
14648 if(this.owner.fireEvent('beforesync', this, html) !== false){
14649 this.el.dom.value = html;
14650 this.owner.fireEvent('sync', this, html);
14656 * Protected method that will not generally be called directly. Pushes the value of the textarea
14657 * into the iframe editor.
14659 pushValue : function(){
14660 if(this.initialized){
14661 var v = this.el.dom.value.trim();
14663 // if(v.length < 1){
14667 if(this.owner.fireEvent('beforepush', this, v) !== false){
14668 var d = (this.doc.body || this.doc.documentElement);
14670 this.cleanUpPaste();
14671 this.el.dom.value = d.innerHTML;
14672 this.owner.fireEvent('push', this, v);
14678 deferFocus : function(){
14679 this.focus.defer(10, this);
14683 focus : function(){
14684 if(this.win && !this.sourceEditMode){
14691 assignDocWin: function()
14693 var iframe = this.iframe;
14696 this.doc = iframe.contentWindow.document;
14697 this.win = iframe.contentWindow;
14699 if (!Roo.get(this.frameId)) {
14702 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
14703 this.win = Roo.get(this.frameId).dom.contentWindow;
14708 initEditor : function(){
14709 //console.log("INIT EDITOR");
14710 this.assignDocWin();
14714 this.doc.designMode="on";
14716 this.doc.write(this.getDocMarkup());
14719 var dbody = (this.doc.body || this.doc.documentElement);
14720 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
14721 // this copies styles from the containing element into thsi one..
14722 // not sure why we need all of this..
14723 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
14725 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
14726 //ss['background-attachment'] = 'fixed'; // w3c
14727 dbody.bgProperties = 'fixed'; // ie
14728 //Roo.DomHelper.applyStyles(dbody, ss);
14729 Roo.EventManager.on(this.doc, {
14730 //'mousedown': this.onEditorEvent,
14731 'mouseup': this.onEditorEvent,
14732 'dblclick': this.onEditorEvent,
14733 'click': this.onEditorEvent,
14734 'keyup': this.onEditorEvent,
14739 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
14741 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
14742 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
14744 this.initialized = true;
14746 this.owner.fireEvent('initialize', this);
14751 onDestroy : function(){
14757 //for (var i =0; i < this.toolbars.length;i++) {
14758 // // fixme - ask toolbars for heights?
14759 // this.toolbars[i].onDestroy();
14762 //this.wrap.dom.innerHTML = '';
14763 //this.wrap.remove();
14768 onFirstFocus : function(){
14770 this.assignDocWin();
14773 this.activated = true;
14776 if(Roo.isGecko){ // prevent silly gecko errors
14778 var s = this.win.getSelection();
14779 if(!s.focusNode || s.focusNode.nodeType != 3){
14780 var r = s.getRangeAt(0);
14781 r.selectNodeContents((this.doc.body || this.doc.documentElement));
14786 this.execCmd('useCSS', true);
14787 this.execCmd('styleWithCSS', false);
14790 this.owner.fireEvent('activate', this);
14794 adjustFont: function(btn){
14795 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
14796 //if(Roo.isSafari){ // safari
14799 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
14800 if(Roo.isSafari){ // safari
14801 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
14802 v = (v < 10) ? 10 : v;
14803 v = (v > 48) ? 48 : v;
14804 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
14809 v = Math.max(1, v+adjust);
14811 this.execCmd('FontSize', v );
14814 onEditorEvent : function(e){
14815 this.owner.fireEvent('editorevent', this, e);
14816 // this.updateToolbar();
14817 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
14820 insertTag : function(tg)
14822 // could be a bit smarter... -> wrap the current selected tRoo..
14823 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
14825 range = this.createRange(this.getSelection());
14826 var wrappingNode = this.doc.createElement(tg.toLowerCase());
14827 wrappingNode.appendChild(range.extractContents());
14828 range.insertNode(wrappingNode);
14835 this.execCmd("formatblock", tg);
14839 insertText : function(txt)
14843 var range = this.createRange();
14844 range.deleteContents();
14845 //alert(Sender.getAttribute('label'));
14847 range.insertNode(this.doc.createTextNode(txt));
14853 * Executes a Midas editor command on the editor document and performs necessary focus and
14854 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
14855 * @param {String} cmd The Midas command
14856 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
14858 relayCmd : function(cmd, value){
14860 this.execCmd(cmd, value);
14861 this.owner.fireEvent('editorevent', this);
14862 //this.updateToolbar();
14863 this.owner.deferFocus();
14867 * Executes a Midas editor command directly on the editor document.
14868 * For visual commands, you should use {@link #relayCmd} instead.
14869 * <b>This should only be called after the editor is initialized.</b>
14870 * @param {String} cmd The Midas command
14871 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
14873 execCmd : function(cmd, value){
14874 this.doc.execCommand(cmd, false, value === undefined ? null : value);
14881 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
14883 * @param {String} text | dom node..
14885 insertAtCursor : function(text)
14890 if(!this.activated){
14896 var r = this.doc.selection.createRange();
14907 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
14911 // from jquery ui (MIT licenced)
14913 var win = this.win;
14915 if (win.getSelection && win.getSelection().getRangeAt) {
14916 range = win.getSelection().getRangeAt(0);
14917 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
14918 range.insertNode(node);
14919 } else if (win.document.selection && win.document.selection.createRange) {
14920 // no firefox support
14921 var txt = typeof(text) == 'string' ? text : text.outerHTML;
14922 win.document.selection.createRange().pasteHTML(txt);
14924 // no firefox support
14925 var txt = typeof(text) == 'string' ? text : text.outerHTML;
14926 this.execCmd('InsertHTML', txt);
14935 mozKeyPress : function(e){
14937 var c = e.getCharCode(), cmd;
14940 c = String.fromCharCode(c).toLowerCase();
14954 this.cleanUpPaste.defer(100, this);
14962 e.preventDefault();
14970 fixKeys : function(){ // load time branching for fastest keydown performance
14972 return function(e){
14973 var k = e.getKey(), r;
14976 r = this.doc.selection.createRange();
14979 r.pasteHTML('    ');
14986 r = this.doc.selection.createRange();
14988 var target = r.parentElement();
14989 if(!target || target.tagName.toLowerCase() != 'li'){
14991 r.pasteHTML('<br />');
14997 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
14998 this.cleanUpPaste.defer(100, this);
15004 }else if(Roo.isOpera){
15005 return function(e){
15006 var k = e.getKey();
15010 this.execCmd('InsertHTML','    ');
15013 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
15014 this.cleanUpPaste.defer(100, this);
15019 }else if(Roo.isSafari){
15020 return function(e){
15021 var k = e.getKey();
15025 this.execCmd('InsertText','\t');
15029 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
15030 this.cleanUpPaste.defer(100, this);
15038 getAllAncestors: function()
15040 var p = this.getSelectedNode();
15043 a.push(p); // push blank onto stack..
15044 p = this.getParentElement();
15048 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
15052 a.push(this.doc.body);
15056 lastSelNode : false,
15059 getSelection : function()
15061 this.assignDocWin();
15062 return Roo.isIE ? this.doc.selection : this.win.getSelection();
15065 getSelectedNode: function()
15067 // this may only work on Gecko!!!
15069 // should we cache this!!!!
15074 var range = this.createRange(this.getSelection()).cloneRange();
15077 var parent = range.parentElement();
15079 var testRange = range.duplicate();
15080 testRange.moveToElementText(parent);
15081 if (testRange.inRange(range)) {
15084 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
15087 parent = parent.parentElement;
15092 // is ancestor a text element.
15093 var ac = range.commonAncestorContainer;
15094 if (ac.nodeType == 3) {
15095 ac = ac.parentNode;
15098 var ar = ac.childNodes;
15101 var other_nodes = [];
15102 var has_other_nodes = false;
15103 for (var i=0;i<ar.length;i++) {
15104 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
15107 // fullly contained node.
15109 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
15114 // probably selected..
15115 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
15116 other_nodes.push(ar[i]);
15120 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
15125 has_other_nodes = true;
15127 if (!nodes.length && other_nodes.length) {
15128 nodes= other_nodes;
15130 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
15136 createRange: function(sel)
15138 // this has strange effects when using with
15139 // top toolbar - not sure if it's a great idea.
15140 //this.editor.contentWindow.focus();
15141 if (typeof sel != "undefined") {
15143 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
15145 return this.doc.createRange();
15148 return this.doc.createRange();
15151 getParentElement: function()
15154 this.assignDocWin();
15155 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
15157 var range = this.createRange(sel);
15160 var p = range.commonAncestorContainer;
15161 while (p.nodeType == 3) { // text node
15172 * Range intersection.. the hard stuff...
15176 * [ -- selected range --- ]
15180 * if end is before start or hits it. fail.
15181 * if start is after end or hits it fail.
15183 * if either hits (but other is outside. - then it's not
15189 // @see http://www.thismuchiknow.co.uk/?p=64.
15190 rangeIntersectsNode : function(range, node)
15192 var nodeRange = node.ownerDocument.createRange();
15194 nodeRange.selectNode(node);
15196 nodeRange.selectNodeContents(node);
15199 var rangeStartRange = range.cloneRange();
15200 rangeStartRange.collapse(true);
15202 var rangeEndRange = range.cloneRange();
15203 rangeEndRange.collapse(false);
15205 var nodeStartRange = nodeRange.cloneRange();
15206 nodeStartRange.collapse(true);
15208 var nodeEndRange = nodeRange.cloneRange();
15209 nodeEndRange.collapse(false);
15211 return rangeStartRange.compareBoundaryPoints(
15212 Range.START_TO_START, nodeEndRange) == -1 &&
15213 rangeEndRange.compareBoundaryPoints(
15214 Range.START_TO_START, nodeStartRange) == 1;
15218 rangeCompareNode : function(range, node)
15220 var nodeRange = node.ownerDocument.createRange();
15222 nodeRange.selectNode(node);
15224 nodeRange.selectNodeContents(node);
15228 range.collapse(true);
15230 nodeRange.collapse(true);
15232 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
15233 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
15235 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
15237 var nodeIsBefore = ss == 1;
15238 var nodeIsAfter = ee == -1;
15240 if (nodeIsBefore && nodeIsAfter)
15242 if (!nodeIsBefore && nodeIsAfter)
15243 return 1; //right trailed.
15245 if (nodeIsBefore && !nodeIsAfter)
15246 return 2; // left trailed.
15251 // private? - in a new class?
15252 cleanUpPaste : function()
15254 // cleans up the whole document..
15255 Roo.log('cleanuppaste');
15257 this.cleanUpChildren(this.doc.body);
15258 var clean = this.cleanWordChars(this.doc.body.innerHTML);
15259 if (clean != this.doc.body.innerHTML) {
15260 this.doc.body.innerHTML = clean;
15265 cleanWordChars : function(input) {// change the chars to hex code
15266 var he = Roo.HtmlEditorCore;
15268 var output = input;
15269 Roo.each(he.swapCodes, function(sw) {
15270 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
15272 output = output.replace(swapper, sw[1]);
15279 cleanUpChildren : function (n)
15281 if (!n.childNodes.length) {
15284 for (var i = n.childNodes.length-1; i > -1 ; i--) {
15285 this.cleanUpChild(n.childNodes[i]);
15292 cleanUpChild : function (node)
15295 //console.log(node);
15296 if (node.nodeName == "#text") {
15297 // clean up silly Windows -- stuff?
15300 if (node.nodeName == "#comment") {
15301 node.parentNode.removeChild(node);
15302 // clean up silly Windows -- stuff?
15306 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
15308 node.parentNode.removeChild(node);
15313 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
15315 // remove <a name=....> as rendering on yahoo mailer is borked with this.
15316 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
15318 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
15319 // remove_keep_children = true;
15322 if (remove_keep_children) {
15323 this.cleanUpChildren(node);
15324 // inserts everything just before this node...
15325 while (node.childNodes.length) {
15326 var cn = node.childNodes[0];
15327 node.removeChild(cn);
15328 node.parentNode.insertBefore(cn, node);
15330 node.parentNode.removeChild(node);
15334 if (!node.attributes || !node.attributes.length) {
15335 this.cleanUpChildren(node);
15339 function cleanAttr(n,v)
15342 if (v.match(/^\./) || v.match(/^\//)) {
15345 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
15348 if (v.match(/^#/)) {
15351 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
15352 node.removeAttribute(n);
15356 function cleanStyle(n,v)
15358 if (v.match(/expression/)) { //XSS?? should we even bother..
15359 node.removeAttribute(n);
15362 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
15363 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
15366 var parts = v.split(/;/);
15369 Roo.each(parts, function(p) {
15370 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
15374 var l = p.split(':').shift().replace(/\s+/g,'');
15375 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
15377 if ( cblack.indexOf(l) > -1) {
15378 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
15379 //node.removeAttribute(n);
15383 // only allow 'c whitelisted system attributes'
15384 if ( cwhite.length && cwhite.indexOf(l) < 0) {
15385 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
15386 //node.removeAttribute(n);
15396 if (clean.length) {
15397 node.setAttribute(n, clean.join(';'));
15399 node.removeAttribute(n);
15405 for (var i = node.attributes.length-1; i > -1 ; i--) {
15406 var a = node.attributes[i];
15409 if (a.name.toLowerCase().substr(0,2)=='on') {
15410 node.removeAttribute(a.name);
15413 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
15414 node.removeAttribute(a.name);
15417 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
15418 cleanAttr(a.name,a.value); // fixme..
15421 if (a.name == 'style') {
15422 cleanStyle(a.name,a.value);
15425 /// clean up MS crap..
15426 // tecnically this should be a list of valid class'es..
15429 if (a.name == 'class') {
15430 if (a.value.match(/^Mso/)) {
15431 node.className = '';
15434 if (a.value.match(/body/)) {
15435 node.className = '';
15446 this.cleanUpChildren(node);
15451 * Clean up MS wordisms...
15453 cleanWord : function(node)
15456 var cleanWordChildren = function()
15458 if (!node.childNodes.length) {
15461 for (var i = node.childNodes.length-1; i > -1 ; i--) {
15462 _t.cleanWord(node.childNodes[i]);
15468 this.cleanWord(this.doc.body);
15471 if (node.nodeName == "#text") {
15472 // clean up silly Windows -- stuff?
15475 if (node.nodeName == "#comment") {
15476 node.parentNode.removeChild(node);
15477 // clean up silly Windows -- stuff?
15481 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
15482 node.parentNode.removeChild(node);
15486 // remove - but keep children..
15487 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
15488 while (node.childNodes.length) {
15489 var cn = node.childNodes[0];
15490 node.removeChild(cn);
15491 node.parentNode.insertBefore(cn, node);
15493 node.parentNode.removeChild(node);
15494 cleanWordChildren();
15498 if (node.className.length) {
15500 var cn = node.className.split(/\W+/);
15502 Roo.each(cn, function(cls) {
15503 if (cls.match(/Mso[a-zA-Z]+/)) {
15508 node.className = cna.length ? cna.join(' ') : '';
15510 node.removeAttribute("class");
15514 if (node.hasAttribute("lang")) {
15515 node.removeAttribute("lang");
15518 if (node.hasAttribute("style")) {
15520 var styles = node.getAttribute("style").split(";");
15522 Roo.each(styles, function(s) {
15523 if (!s.match(/:/)) {
15526 var kv = s.split(":");
15527 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
15530 // what ever is left... we allow.
15533 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
15534 if (!nstyle.length) {
15535 node.removeAttribute('style');
15539 cleanWordChildren();
15543 domToHTML : function(currentElement, depth, nopadtext) {
15545 depth = depth || 0;
15546 nopadtext = nopadtext || false;
15548 if (!currentElement) {
15549 return this.domToHTML(this.doc.body);
15552 //Roo.log(currentElement);
15554 var allText = false;
15555 var nodeName = currentElement.nodeName;
15556 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
15558 if (nodeName == '#text') {
15559 return currentElement.nodeValue;
15564 if (nodeName != 'BODY') {
15567 // Prints the node tagName, such as <A>, <IMG>, etc
15570 for(i = 0; i < currentElement.attributes.length;i++) {
15572 var aname = currentElement.attributes.item(i).name;
15573 if (!currentElement.attributes.item(i).value.length) {
15576 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
15579 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
15588 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
15591 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
15596 // Traverse the tree
15598 var currentElementChild = currentElement.childNodes.item(i);
15599 var allText = true;
15600 var innerHTML = '';
15602 while (currentElementChild) {
15603 // Formatting code (indent the tree so it looks nice on the screen)
15604 var nopad = nopadtext;
15605 if (lastnode == 'SPAN') {
15609 if (currentElementChild.nodeName == '#text') {
15610 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
15611 if (!nopad && toadd.length > 80) {
15612 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
15614 innerHTML += toadd;
15617 currentElementChild = currentElement.childNodes.item(i);
15623 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
15625 // Recursively traverse the tree structure of the child node
15626 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
15627 lastnode = currentElementChild.nodeName;
15629 currentElementChild=currentElement.childNodes.item(i);
15635 // The remaining code is mostly for formatting the tree
15636 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
15641 ret+= "</"+tagName+">";
15647 // hide stuff that is not compatible
15661 * @event specialkey
15665 * @cfg {String} fieldClass @hide
15668 * @cfg {String} focusClass @hide
15671 * @cfg {String} autoCreate @hide
15674 * @cfg {String} inputType @hide
15677 * @cfg {String} invalidClass @hide
15680 * @cfg {String} invalidText @hide
15683 * @cfg {String} msgFx @hide
15686 * @cfg {String} validateOnBlur @hide
15690 Roo.HtmlEditorCore.white = [
15691 'area', 'br', 'img', 'input', 'hr', 'wbr',
15693 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
15694 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
15695 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
15696 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
15697 'table', 'ul', 'xmp',
15699 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
15702 'dir', 'menu', 'ol', 'ul', 'dl',
15708 Roo.HtmlEditorCore.black = [
15709 // 'embed', 'object', // enable - backend responsiblity to clean thiese
15711 'base', 'basefont', 'bgsound', 'blink', 'body',
15712 'frame', 'frameset', 'head', 'html', 'ilayer',
15713 'iframe', 'layer', 'link', 'meta', 'object',
15714 'script', 'style' ,'title', 'xml' // clean later..
15716 Roo.HtmlEditorCore.clean = [
15717 'script', 'style', 'title', 'xml'
15719 Roo.HtmlEditorCore.remove = [
15724 Roo.HtmlEditorCore.ablack = [
15728 Roo.HtmlEditorCore.aclean = [
15729 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
15733 Roo.HtmlEditorCore.pwhite= [
15734 'http', 'https', 'mailto'
15737 // white listed style attributes.
15738 Roo.HtmlEditorCore.cwhite= [
15739 // 'text-align', /// default is to allow most things..
15745 // black listed style attributes.
15746 Roo.HtmlEditorCore.cblack= [
15747 // 'font-size' -- this can be set by the project
15751 Roo.HtmlEditorCore.swapCodes =[
15770 * @class Roo.bootstrap.HtmlEditor
15771 * @extends Roo.bootstrap.TextArea
15772 * Bootstrap HtmlEditor class
15775 * Create a new HtmlEditor
15776 * @param {Object} config The config object
15779 Roo.bootstrap.HtmlEditor = function(config){
15780 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
15781 if (!this.toolbars) {
15782 this.toolbars = [];
15784 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
15787 * @event initialize
15788 * Fires when the editor is fully initialized (including the iframe)
15789 * @param {HtmlEditor} this
15794 * Fires when the editor is first receives the focus. Any insertion must wait
15795 * until after this event.
15796 * @param {HtmlEditor} this
15800 * @event beforesync
15801 * Fires before the textarea is updated with content from the editor iframe. Return false
15802 * to cancel the sync.
15803 * @param {HtmlEditor} this
15804 * @param {String} html
15808 * @event beforepush
15809 * Fires before the iframe editor is updated with content from the textarea. Return false
15810 * to cancel the push.
15811 * @param {HtmlEditor} this
15812 * @param {String} html
15817 * Fires when the textarea is updated with content from the editor iframe.
15818 * @param {HtmlEditor} this
15819 * @param {String} html
15824 * Fires when the iframe editor is updated with content from the textarea.
15825 * @param {HtmlEditor} this
15826 * @param {String} html
15830 * @event editmodechange
15831 * Fires when the editor switches edit modes
15832 * @param {HtmlEditor} this
15833 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
15835 editmodechange: true,
15837 * @event editorevent
15838 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
15839 * @param {HtmlEditor} this
15843 * @event firstfocus
15844 * Fires when on first focus - needed by toolbars..
15845 * @param {HtmlEditor} this
15850 * Auto save the htmlEditor value as a file into Events
15851 * @param {HtmlEditor} this
15855 * @event savedpreview
15856 * preview the saved version of htmlEditor
15857 * @param {HtmlEditor} this
15864 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
15868 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
15873 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
15878 * @cfg {Number} height (in pixels)
15882 * @cfg {Number} width (in pixels)
15887 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
15890 stylesheets: false,
15895 // private properties
15896 validationEvent : false,
15898 initialized : false,
15901 onFocus : Roo.emptyFn,
15903 hideMode:'offsets',
15906 tbContainer : false,
15908 toolbarContainer :function() {
15909 return this.wrap.select('.x-html-editor-tb',true).first();
15913 * Protected method that will not generally be called directly. It
15914 * is called when the editor creates its toolbar. Override this method if you need to
15915 * add custom toolbar buttons.
15916 * @param {HtmlEditor} editor
15918 createToolbar : function(){
15920 Roo.log("create toolbars");
15922 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
15923 this.toolbars[0].render(this.toolbarContainer());
15927 // if (!editor.toolbars || !editor.toolbars.length) {
15928 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
15931 // for (var i =0 ; i < editor.toolbars.length;i++) {
15932 // editor.toolbars[i] = Roo.factory(
15933 // typeof(editor.toolbars[i]) == 'string' ?
15934 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
15935 // Roo.bootstrap.HtmlEditor);
15936 // editor.toolbars[i].init(editor);
15942 onRender : function(ct, position)
15944 // Roo.log("Call onRender: " + this.xtype);
15946 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
15948 this.wrap = this.inputEl().wrap({
15949 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
15952 this.editorcore.onRender(ct, position);
15954 if (this.resizable) {
15955 this.resizeEl = new Roo.Resizable(this.wrap, {
15959 minHeight : this.height,
15960 height: this.height,
15961 handles : this.resizable,
15964 resize : function(r, w, h) {
15965 _t.onResize(w,h); // -something
15971 this.createToolbar(this);
15974 if(!this.width && this.resizable){
15975 this.setSize(this.wrap.getSize());
15977 if (this.resizeEl) {
15978 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
15979 // should trigger onReize..
15985 onResize : function(w, h)
15987 Roo.log('resize: ' +w + ',' + h );
15988 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
15992 if(this.inputEl() ){
15993 if(typeof w == 'number'){
15994 var aw = w - this.wrap.getFrameWidth('lr');
15995 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
15998 if(typeof h == 'number'){
15999 var tbh = -11; // fixme it needs to tool bar size!
16000 for (var i =0; i < this.toolbars.length;i++) {
16001 // fixme - ask toolbars for heights?
16002 tbh += this.toolbars[i].el.getHeight();
16003 //if (this.toolbars[i].footer) {
16004 // tbh += this.toolbars[i].footer.el.getHeight();
16012 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
16013 ah -= 5; // knock a few pixes off for look..
16014 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
16018 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
16019 this.editorcore.onResize(ew,eh);
16024 * Toggles the editor between standard and source edit mode.
16025 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16027 toggleSourceEdit : function(sourceEditMode)
16029 this.editorcore.toggleSourceEdit(sourceEditMode);
16031 if(this.editorcore.sourceEditMode){
16032 Roo.log('editor - showing textarea');
16035 // Roo.log(this.syncValue());
16037 this.inputEl().removeClass('hide');
16038 this.inputEl().dom.removeAttribute('tabIndex');
16039 this.inputEl().focus();
16041 Roo.log('editor - hiding textarea');
16043 // Roo.log(this.pushValue());
16046 this.inputEl().addClass('hide');
16047 this.inputEl().dom.setAttribute('tabIndex', -1);
16048 //this.deferFocus();
16051 if(this.resizable){
16052 this.setSize(this.wrap.getSize());
16055 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
16058 // private (for BoxComponent)
16059 adjustSize : Roo.BoxComponent.prototype.adjustSize,
16061 // private (for BoxComponent)
16062 getResizeEl : function(){
16066 // private (for BoxComponent)
16067 getPositionEl : function(){
16072 initEvents : function(){
16073 this.originalValue = this.getValue();
16077 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
16080 // markInvalid : Roo.emptyFn,
16082 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
16085 // clearInvalid : Roo.emptyFn,
16087 setValue : function(v){
16088 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
16089 this.editorcore.pushValue();
16094 deferFocus : function(){
16095 this.focus.defer(10, this);
16099 focus : function(){
16100 this.editorcore.focus();
16106 onDestroy : function(){
16112 for (var i =0; i < this.toolbars.length;i++) {
16113 // fixme - ask toolbars for heights?
16114 this.toolbars[i].onDestroy();
16117 this.wrap.dom.innerHTML = '';
16118 this.wrap.remove();
16123 onFirstFocus : function(){
16124 //Roo.log("onFirstFocus");
16125 this.editorcore.onFirstFocus();
16126 for (var i =0; i < this.toolbars.length;i++) {
16127 this.toolbars[i].onFirstFocus();
16133 syncValue : function()
16135 this.editorcore.syncValue();
16138 pushValue : function()
16140 this.editorcore.pushValue();
16144 // hide stuff that is not compatible
16158 * @event specialkey
16162 * @cfg {String} fieldClass @hide
16165 * @cfg {String} focusClass @hide
16168 * @cfg {String} autoCreate @hide
16171 * @cfg {String} inputType @hide
16174 * @cfg {String} invalidClass @hide
16177 * @cfg {String} invalidText @hide
16180 * @cfg {String} msgFx @hide
16183 * @cfg {String} validateOnBlur @hide
16192 Roo.namespace('Roo.bootstrap.htmleditor');
16194 * @class Roo.bootstrap.HtmlEditorToolbar1
16199 new Roo.bootstrap.HtmlEditor({
16202 new Roo.bootstrap.HtmlEditorToolbar1({
16203 disable : { fonts: 1 , format: 1, ..., ... , ...],
16209 * @cfg {Object} disable List of elements to disable..
16210 * @cfg {Array} btns List of additional buttons.
16214 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
16217 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
16220 Roo.apply(this, config);
16222 // default disabled, based on 'good practice'..
16223 this.disable = this.disable || {};
16224 Roo.applyIf(this.disable, {
16227 specialElements : true
16229 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
16231 this.editor = config.editor;
16232 this.editorcore = config.editor.editorcore;
16234 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
16236 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
16237 // dont call parent... till later.
16239 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
16244 editorcore : false,
16249 "h1","h2","h3","h4","h5","h6",
16251 "abbr", "acronym", "address", "cite", "samp", "var",
16255 onRender : function(ct, position)
16257 // Roo.log("Call onRender: " + this.xtype);
16259 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
16261 this.el.dom.style.marginBottom = '0';
16263 var editorcore = this.editorcore;
16264 var editor= this.editor;
16267 var btn = function(id,cmd , toggle, handler){
16269 var event = toggle ? 'toggle' : 'click';
16274 xns: Roo.bootstrap,
16277 enableToggle:toggle !== false,
16279 pressed : toggle ? false : null,
16282 a.listeners[toggle ? 'toggle' : 'click'] = function() {
16283 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
16292 xns: Roo.bootstrap,
16293 glyphicon : 'font',
16297 xns: Roo.bootstrap,
16301 Roo.each(this.formats, function(f) {
16302 style.menu.items.push({
16304 xns: Roo.bootstrap,
16305 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
16310 editorcore.insertTag(this.tagname);
16317 children.push(style);
16320 btn('bold',false,true);
16321 btn('italic',false,true);
16322 btn('align-left', 'justifyleft',true);
16323 btn('align-center', 'justifycenter',true);
16324 btn('align-right' , 'justifyright',true);
16325 btn('link', false, false, function(btn) {
16326 //Roo.log("create link?");
16327 var url = prompt(this.createLinkText, this.defaultLinkValue);
16328 if(url && url != 'http:/'+'/'){
16329 this.editorcore.relayCmd('createlink', url);
16332 btn('list','insertunorderedlist',true);
16333 btn('pencil', false,true, function(btn){
16336 this.toggleSourceEdit(btn.pressed);
16342 xns: Roo.bootstrap,
16347 xns: Roo.bootstrap,
16352 cog.menu.items.push({
16354 xns: Roo.bootstrap,
16355 html : Clean styles,
16360 editorcore.insertTag(this.tagname);
16369 this.xtype = 'NavSimplebar';
16371 for(var i=0;i< children.length;i++) {
16373 this.buttons.add(this.addxtypeChild(children[i]));
16377 editor.on('editorevent', this.updateToolbar, this);
16379 onBtnClick : function(id)
16381 this.editorcore.relayCmd(id);
16382 this.editorcore.focus();
16386 * Protected method that will not generally be called directly. It triggers
16387 * a toolbar update by reading the markup state of the current selection in the editor.
16389 updateToolbar: function(){
16391 if(!this.editorcore.activated){
16392 this.editor.onFirstFocus(); // is this neeed?
16396 var btns = this.buttons;
16397 var doc = this.editorcore.doc;
16398 btns.get('bold').setActive(doc.queryCommandState('bold'));
16399 btns.get('italic').setActive(doc.queryCommandState('italic'));
16400 //btns.get('underline').setActive(doc.queryCommandState('underline'));
16402 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
16403 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
16404 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
16406 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
16407 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
16410 var ans = this.editorcore.getAllAncestors();
16411 if (this.formatCombo) {
16414 var store = this.formatCombo.store;
16415 this.formatCombo.setValue("");
16416 for (var i =0; i < ans.length;i++) {
16417 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
16419 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
16427 // hides menus... - so this cant be on a menu...
16428 Roo.bootstrap.MenuMgr.hideAll();
16430 Roo.bootstrap.MenuMgr.hideAll();
16431 //this.editorsyncValue();
16433 onFirstFocus: function() {
16434 this.buttons.each(function(item){
16438 toggleSourceEdit : function(sourceEditMode){
16441 if(sourceEditMode){
16442 Roo.log("disabling buttons");
16443 this.buttons.each( function(item){
16444 if(item.cmd != 'pencil'){
16450 Roo.log("enabling buttons");
16451 if(this.editorcore.initialized){
16452 this.buttons.each( function(item){
16458 Roo.log("calling toggole on editor");
16459 // tell the editor that it's been pressed..
16460 this.editor.toggleSourceEdit(sourceEditMode);
16470 * Ext JS Library 1.1.1
16471 * Copyright(c) 2006-2007, Ext JS, LLC.
16473 * Originally Released Under LGPL - original licence link has changed is not relivant.
16476 * <script type="text/javascript">
16481 * @class Roo.grid.ColumnModel
16482 * @extends Roo.util.Observable
16483 * This is the default implementation of a ColumnModel used by the Grid. It defines
16484 * the columns in the grid.
16487 var colModel = new Roo.grid.ColumnModel([
16488 {header: "Ticker", width: 60, sortable: true, locked: true},
16489 {header: "Company Name", width: 150, sortable: true},
16490 {header: "Market Cap.", width: 100, sortable: true},
16491 {header: "$ Sales", width: 100, sortable: true, renderer: money},
16492 {header: "Employees", width: 100, sortable: true, resizable: false}
16497 * The config options listed for this class are options which may appear in each
16498 * individual column definition.
16499 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
16501 * @param {Object} config An Array of column config objects. See this class's
16502 * config objects for details.
16504 Roo.grid.ColumnModel = function(config){
16506 * The config passed into the constructor
16508 this.config = config;
16511 // if no id, create one
16512 // if the column does not have a dataIndex mapping,
16513 // map it to the order it is in the config
16514 for(var i = 0, len = config.length; i < len; i++){
16516 if(typeof c.dataIndex == "undefined"){
16519 if(typeof c.renderer == "string"){
16520 c.renderer = Roo.util.Format[c.renderer];
16522 if(typeof c.id == "undefined"){
16525 if(c.editor && c.editor.xtype){
16526 c.editor = Roo.factory(c.editor, Roo.grid);
16528 if(c.editor && c.editor.isFormField){
16529 c.editor = new Roo.grid.GridEditor(c.editor);
16531 this.lookup[c.id] = c;
16535 * The width of columns which have no width specified (defaults to 100)
16538 this.defaultWidth = 100;
16541 * Default sortable of columns which have no sortable specified (defaults to false)
16544 this.defaultSortable = false;
16548 * @event widthchange
16549 * Fires when the width of a column changes.
16550 * @param {ColumnModel} this
16551 * @param {Number} columnIndex The column index
16552 * @param {Number} newWidth The new width
16554 "widthchange": true,
16556 * @event headerchange
16557 * Fires when the text of a header changes.
16558 * @param {ColumnModel} this
16559 * @param {Number} columnIndex The column index
16560 * @param {Number} newText The new header text
16562 "headerchange": true,
16564 * @event hiddenchange
16565 * Fires when a column is hidden or "unhidden".
16566 * @param {ColumnModel} this
16567 * @param {Number} columnIndex The column index
16568 * @param {Boolean} hidden true if hidden, false otherwise
16570 "hiddenchange": true,
16572 * @event columnmoved
16573 * Fires when a column is moved.
16574 * @param {ColumnModel} this
16575 * @param {Number} oldIndex
16576 * @param {Number} newIndex
16578 "columnmoved" : true,
16580 * @event columlockchange
16581 * Fires when a column's locked state is changed
16582 * @param {ColumnModel} this
16583 * @param {Number} colIndex
16584 * @param {Boolean} locked true if locked
16586 "columnlockchange" : true
16588 Roo.grid.ColumnModel.superclass.constructor.call(this);
16590 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
16592 * @cfg {String} header The header text to display in the Grid view.
16595 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
16596 * {@link Roo.data.Record} definition from which to draw the column's value. If not
16597 * specified, the column's index is used as an index into the Record's data Array.
16600 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
16601 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
16604 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
16605 * Defaults to the value of the {@link #defaultSortable} property.
16606 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
16609 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
16612 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
16615 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
16618 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
16621 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
16622 * given the cell's data value. See {@link #setRenderer}. If not specified, the
16623 * default renderer uses the raw data value.
16626 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
16629 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
16633 * Returns the id of the column at the specified index.
16634 * @param {Number} index The column index
16635 * @return {String} the id
16637 getColumnId : function(index){
16638 return this.config[index].id;
16642 * Returns the column for a specified id.
16643 * @param {String} id The column id
16644 * @return {Object} the column
16646 getColumnById : function(id){
16647 return this.lookup[id];
16652 * Returns the column for a specified dataIndex.
16653 * @param {String} dataIndex The column dataIndex
16654 * @return {Object|Boolean} the column or false if not found
16656 getColumnByDataIndex: function(dataIndex){
16657 var index = this.findColumnIndex(dataIndex);
16658 return index > -1 ? this.config[index] : false;
16662 * Returns the index for a specified column id.
16663 * @param {String} id The column id
16664 * @return {Number} the index, or -1 if not found
16666 getIndexById : function(id){
16667 for(var i = 0, len = this.config.length; i < len; i++){
16668 if(this.config[i].id == id){
16676 * Returns the index for a specified column dataIndex.
16677 * @param {String} dataIndex The column dataIndex
16678 * @return {Number} the index, or -1 if not found
16681 findColumnIndex : function(dataIndex){
16682 for(var i = 0, len = this.config.length; i < len; i++){
16683 if(this.config[i].dataIndex == dataIndex){
16691 moveColumn : function(oldIndex, newIndex){
16692 var c = this.config[oldIndex];
16693 this.config.splice(oldIndex, 1);
16694 this.config.splice(newIndex, 0, c);
16695 this.dataMap = null;
16696 this.fireEvent("columnmoved", this, oldIndex, newIndex);
16699 isLocked : function(colIndex){
16700 return this.config[colIndex].locked === true;
16703 setLocked : function(colIndex, value, suppressEvent){
16704 if(this.isLocked(colIndex) == value){
16707 this.config[colIndex].locked = value;
16708 if(!suppressEvent){
16709 this.fireEvent("columnlockchange", this, colIndex, value);
16713 getTotalLockedWidth : function(){
16714 var totalWidth = 0;
16715 for(var i = 0; i < this.config.length; i++){
16716 if(this.isLocked(i) && !this.isHidden(i)){
16717 this.totalWidth += this.getColumnWidth(i);
16723 getLockedCount : function(){
16724 for(var i = 0, len = this.config.length; i < len; i++){
16725 if(!this.isLocked(i)){
16732 * Returns the number of columns.
16735 getColumnCount : function(visibleOnly){
16736 if(visibleOnly === true){
16738 for(var i = 0, len = this.config.length; i < len; i++){
16739 if(!this.isHidden(i)){
16745 return this.config.length;
16749 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
16750 * @param {Function} fn
16751 * @param {Object} scope (optional)
16752 * @return {Array} result
16754 getColumnsBy : function(fn, scope){
16756 for(var i = 0, len = this.config.length; i < len; i++){
16757 var c = this.config[i];
16758 if(fn.call(scope||this, c, i) === true){
16766 * Returns true if the specified column is sortable.
16767 * @param {Number} col The column index
16768 * @return {Boolean}
16770 isSortable : function(col){
16771 if(typeof this.config[col].sortable == "undefined"){
16772 return this.defaultSortable;
16774 return this.config[col].sortable;
16778 * Returns the rendering (formatting) function defined for the column.
16779 * @param {Number} col The column index.
16780 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
16782 getRenderer : function(col){
16783 if(!this.config[col].renderer){
16784 return Roo.grid.ColumnModel.defaultRenderer;
16786 return this.config[col].renderer;
16790 * Sets the rendering (formatting) function for a column.
16791 * @param {Number} col The column index
16792 * @param {Function} fn The function to use to process the cell's raw data
16793 * to return HTML markup for the grid view. The render function is called with
16794 * the following parameters:<ul>
16795 * <li>Data value.</li>
16796 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
16797 * <li>css A CSS style string to apply to the table cell.</li>
16798 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
16799 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
16800 * <li>Row index</li>
16801 * <li>Column index</li>
16802 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
16804 setRenderer : function(col, fn){
16805 this.config[col].renderer = fn;
16809 * Returns the width for the specified column.
16810 * @param {Number} col The column index
16813 getColumnWidth : function(col){
16814 return this.config[col].width * 1 || this.defaultWidth;
16818 * Sets the width for a column.
16819 * @param {Number} col The column index
16820 * @param {Number} width The new width
16822 setColumnWidth : function(col, width, suppressEvent){
16823 this.config[col].width = width;
16824 this.totalWidth = null;
16825 if(!suppressEvent){
16826 this.fireEvent("widthchange", this, col, width);
16831 * Returns the total width of all columns.
16832 * @param {Boolean} includeHidden True to include hidden column widths
16835 getTotalWidth : function(includeHidden){
16836 if(!this.totalWidth){
16837 this.totalWidth = 0;
16838 for(var i = 0, len = this.config.length; i < len; i++){
16839 if(includeHidden || !this.isHidden(i)){
16840 this.totalWidth += this.getColumnWidth(i);
16844 return this.totalWidth;
16848 * Returns the header for the specified column.
16849 * @param {Number} col The column index
16852 getColumnHeader : function(col){
16853 return this.config[col].header;
16857 * Sets the header for a column.
16858 * @param {Number} col The column index
16859 * @param {String} header The new header
16861 setColumnHeader : function(col, header){
16862 this.config[col].header = header;
16863 this.fireEvent("headerchange", this, col, header);
16867 * Returns the tooltip for the specified column.
16868 * @param {Number} col The column index
16871 getColumnTooltip : function(col){
16872 return this.config[col].tooltip;
16875 * Sets the tooltip for a column.
16876 * @param {Number} col The column index
16877 * @param {String} tooltip The new tooltip
16879 setColumnTooltip : function(col, tooltip){
16880 this.config[col].tooltip = tooltip;
16884 * Returns the dataIndex for the specified column.
16885 * @param {Number} col The column index
16888 getDataIndex : function(col){
16889 return this.config[col].dataIndex;
16893 * Sets the dataIndex for a column.
16894 * @param {Number} col The column index
16895 * @param {Number} dataIndex The new dataIndex
16897 setDataIndex : function(col, dataIndex){
16898 this.config[col].dataIndex = dataIndex;
16904 * Returns true if the cell is editable.
16905 * @param {Number} colIndex The column index
16906 * @param {Number} rowIndex The row index
16907 * @return {Boolean}
16909 isCellEditable : function(colIndex, rowIndex){
16910 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
16914 * Returns the editor defined for the cell/column.
16915 * return false or null to disable editing.
16916 * @param {Number} colIndex The column index
16917 * @param {Number} rowIndex The row index
16920 getCellEditor : function(colIndex, rowIndex){
16921 return this.config[colIndex].editor;
16925 * Sets if a column is editable.
16926 * @param {Number} col The column index
16927 * @param {Boolean} editable True if the column is editable
16929 setEditable : function(col, editable){
16930 this.config[col].editable = editable;
16935 * Returns true if the column is hidden.
16936 * @param {Number} colIndex The column index
16937 * @return {Boolean}
16939 isHidden : function(colIndex){
16940 return this.config[colIndex].hidden;
16945 * Returns true if the column width cannot be changed
16947 isFixed : function(colIndex){
16948 return this.config[colIndex].fixed;
16952 * Returns true if the column can be resized
16953 * @return {Boolean}
16955 isResizable : function(colIndex){
16956 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
16959 * Sets if a column is hidden.
16960 * @param {Number} colIndex The column index
16961 * @param {Boolean} hidden True if the column is hidden
16963 setHidden : function(colIndex, hidden){
16964 this.config[colIndex].hidden = hidden;
16965 this.totalWidth = null;
16966 this.fireEvent("hiddenchange", this, colIndex, hidden);
16970 * Sets the editor for a column.
16971 * @param {Number} col The column index
16972 * @param {Object} editor The editor object
16974 setEditor : function(col, editor){
16975 this.config[col].editor = editor;
16979 Roo.grid.ColumnModel.defaultRenderer = function(value){
16980 if(typeof value == "string" && value.length < 1){
16986 // Alias for backwards compatibility
16987 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
16990 * @class Roo.bootstrap.Table.AbstractSelectionModel
16991 * @extends Roo.util.Observable
16992 * Abstract base class for grid SelectionModels. It provides the interface that should be
16993 * implemented by descendant classes. This class should not be directly instantiated.
16996 Roo.bootstrap.Table.AbstractSelectionModel = function(){
16997 this.locked = false;
16998 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
17002 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
17003 /** @ignore Called by the grid automatically. Do not call directly. */
17004 init : function(grid){
17010 * Locks the selections.
17013 this.locked = true;
17017 * Unlocks the selections.
17019 unlock : function(){
17020 this.locked = false;
17024 * Returns true if the selections are locked.
17025 * @return {Boolean}
17027 isLocked : function(){
17028 return this.locked;
17032 * @extends Roo.bootstrap.Table.AbstractSelectionModel
17033 * @class Roo.bootstrap.Table.RowSelectionModel
17034 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
17035 * It supports multiple selections and keyboard selection/navigation.
17037 * @param {Object} config
17040 Roo.bootstrap.Table.RowSelectionModel = function(config){
17041 Roo.apply(this, config);
17042 this.selections = new Roo.util.MixedCollection(false, function(o){
17047 this.lastActive = false;
17051 * @event selectionchange
17052 * Fires when the selection changes
17053 * @param {SelectionModel} this
17055 "selectionchange" : true,
17057 * @event afterselectionchange
17058 * Fires after the selection changes (eg. by key press or clicking)
17059 * @param {SelectionModel} this
17061 "afterselectionchange" : true,
17063 * @event beforerowselect
17064 * Fires when a row is selected being selected, return false to cancel.
17065 * @param {SelectionModel} this
17066 * @param {Number} rowIndex The selected index
17067 * @param {Boolean} keepExisting False if other selections will be cleared
17069 "beforerowselect" : true,
17072 * Fires when a row is selected.
17073 * @param {SelectionModel} this
17074 * @param {Number} rowIndex The selected index
17075 * @param {Roo.data.Record} r The record
17077 "rowselect" : true,
17079 * @event rowdeselect
17080 * Fires when a row is deselected.
17081 * @param {SelectionModel} this
17082 * @param {Number} rowIndex The selected index
17084 "rowdeselect" : true
17086 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
17087 this.locked = false;
17090 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
17092 * @cfg {Boolean} singleSelect
17093 * True to allow selection of only one row at a time (defaults to false)
17095 singleSelect : false,
17098 initEvents : function(){
17100 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
17101 this.grid.on("mousedown", this.handleMouseDown, this);
17102 }else{ // allow click to work like normal
17103 this.grid.on("rowclick", this.handleDragableRowClick, this);
17106 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
17107 "up" : function(e){
17109 this.selectPrevious(e.shiftKey);
17110 }else if(this.last !== false && this.lastActive !== false){
17111 var last = this.last;
17112 this.selectRange(this.last, this.lastActive-1);
17113 this.grid.getView().focusRow(this.lastActive);
17114 if(last !== false){
17118 this.selectFirstRow();
17120 this.fireEvent("afterselectionchange", this);
17122 "down" : function(e){
17124 this.selectNext(e.shiftKey);
17125 }else if(this.last !== false && this.lastActive !== false){
17126 var last = this.last;
17127 this.selectRange(this.last, this.lastActive+1);
17128 this.grid.getView().focusRow(this.lastActive);
17129 if(last !== false){
17133 this.selectFirstRow();
17135 this.fireEvent("afterselectionchange", this);
17140 var view = this.grid.view;
17141 view.on("refresh", this.onRefresh, this);
17142 view.on("rowupdated", this.onRowUpdated, this);
17143 view.on("rowremoved", this.onRemove, this);
17147 onRefresh : function(){
17148 var ds = this.grid.dataSource, i, v = this.grid.view;
17149 var s = this.selections;
17150 s.each(function(r){
17151 if((i = ds.indexOfId(r.id)) != -1){
17160 onRemove : function(v, index, r){
17161 this.selections.remove(r);
17165 onRowUpdated : function(v, index, r){
17166 if(this.isSelected(r)){
17167 v.onRowSelect(index);
17173 * @param {Array} records The records to select
17174 * @param {Boolean} keepExisting (optional) True to keep existing selections
17176 selectRecords : function(records, keepExisting){
17178 this.clearSelections();
17180 var ds = this.grid.dataSource;
17181 for(var i = 0, len = records.length; i < len; i++){
17182 this.selectRow(ds.indexOf(records[i]), true);
17187 * Gets the number of selected rows.
17190 getCount : function(){
17191 return this.selections.length;
17195 * Selects the first row in the grid.
17197 selectFirstRow : function(){
17202 * Select the last row.
17203 * @param {Boolean} keepExisting (optional) True to keep existing selections
17205 selectLastRow : function(keepExisting){
17206 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
17210 * Selects the row immediately following the last selected row.
17211 * @param {Boolean} keepExisting (optional) True to keep existing selections
17213 selectNext : function(keepExisting){
17214 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
17215 this.selectRow(this.last+1, keepExisting);
17216 this.grid.getView().focusRow(this.last);
17221 * Selects the row that precedes the last selected row.
17222 * @param {Boolean} keepExisting (optional) True to keep existing selections
17224 selectPrevious : function(keepExisting){
17226 this.selectRow(this.last-1, keepExisting);
17227 this.grid.getView().focusRow(this.last);
17232 * Returns the selected records
17233 * @return {Array} Array of selected records
17235 getSelections : function(){
17236 return [].concat(this.selections.items);
17240 * Returns the first selected record.
17243 getSelected : function(){
17244 return this.selections.itemAt(0);
17249 * Clears all selections.
17251 clearSelections : function(fast){
17252 if(this.locked) return;
17254 var ds = this.grid.dataSource;
17255 var s = this.selections;
17256 s.each(function(r){
17257 this.deselectRow(ds.indexOfId(r.id));
17261 this.selections.clear();
17268 * Selects all rows.
17270 selectAll : function(){
17271 if(this.locked) return;
17272 this.selections.clear();
17273 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
17274 this.selectRow(i, true);
17279 * Returns True if there is a selection.
17280 * @return {Boolean}
17282 hasSelection : function(){
17283 return this.selections.length > 0;
17287 * Returns True if the specified row is selected.
17288 * @param {Number/Record} record The record or index of the record to check
17289 * @return {Boolean}
17291 isSelected : function(index){
17292 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
17293 return (r && this.selections.key(r.id) ? true : false);
17297 * Returns True if the specified record id is selected.
17298 * @param {String} id The id of record to check
17299 * @return {Boolean}
17301 isIdSelected : function(id){
17302 return (this.selections.key(id) ? true : false);
17306 handleMouseDown : function(e, t){
17307 var view = this.grid.getView(), rowIndex;
17308 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
17311 if(e.shiftKey && this.last !== false){
17312 var last = this.last;
17313 this.selectRange(last, rowIndex, e.ctrlKey);
17314 this.last = last; // reset the last
17315 view.focusRow(rowIndex);
17317 var isSelected = this.isSelected(rowIndex);
17318 if(e.button !== 0 && isSelected){
17319 view.focusRow(rowIndex);
17320 }else if(e.ctrlKey && isSelected){
17321 this.deselectRow(rowIndex);
17322 }else if(!isSelected){
17323 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
17324 view.focusRow(rowIndex);
17327 this.fireEvent("afterselectionchange", this);
17330 handleDragableRowClick : function(grid, rowIndex, e)
17332 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
17333 this.selectRow(rowIndex, false);
17334 grid.view.focusRow(rowIndex);
17335 this.fireEvent("afterselectionchange", this);
17340 * Selects multiple rows.
17341 * @param {Array} rows Array of the indexes of the row to select
17342 * @param {Boolean} keepExisting (optional) True to keep existing selections
17344 selectRows : function(rows, keepExisting){
17346 this.clearSelections();
17348 for(var i = 0, len = rows.length; i < len; i++){
17349 this.selectRow(rows[i], true);
17354 * Selects a range of rows. All rows in between startRow and endRow are also selected.
17355 * @param {Number} startRow The index of the first row in the range
17356 * @param {Number} endRow The index of the last row in the range
17357 * @param {Boolean} keepExisting (optional) True to retain existing selections
17359 selectRange : function(startRow, endRow, keepExisting){
17360 if(this.locked) return;
17362 this.clearSelections();
17364 if(startRow <= endRow){
17365 for(var i = startRow; i <= endRow; i++){
17366 this.selectRow(i, true);
17369 for(var i = startRow; i >= endRow; i--){
17370 this.selectRow(i, true);
17376 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
17377 * @param {Number} startRow The index of the first row in the range
17378 * @param {Number} endRow The index of the last row in the range
17380 deselectRange : function(startRow, endRow, preventViewNotify){
17381 if(this.locked) return;
17382 for(var i = startRow; i <= endRow; i++){
17383 this.deselectRow(i, preventViewNotify);
17389 * @param {Number} row The index of the row to select
17390 * @param {Boolean} keepExisting (optional) True to keep existing selections
17392 selectRow : function(index, keepExisting, preventViewNotify){
17393 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
17394 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
17395 if(!keepExisting || this.singleSelect){
17396 this.clearSelections();
17398 var r = this.grid.dataSource.getAt(index);
17399 this.selections.add(r);
17400 this.last = this.lastActive = index;
17401 if(!preventViewNotify){
17402 this.grid.getView().onRowSelect(index);
17404 this.fireEvent("rowselect", this, index, r);
17405 this.fireEvent("selectionchange", this);
17411 * @param {Number} row The index of the row to deselect
17413 deselectRow : function(index, preventViewNotify){
17414 if(this.locked) return;
17415 if(this.last == index){
17418 if(this.lastActive == index){
17419 this.lastActive = false;
17421 var r = this.grid.dataSource.getAt(index);
17422 this.selections.remove(r);
17423 if(!preventViewNotify){
17424 this.grid.getView().onRowDeselect(index);
17426 this.fireEvent("rowdeselect", this, index);
17427 this.fireEvent("selectionchange", this);
17431 restoreLast : function(){
17433 this.last = this._last;
17438 acceptsNav : function(row, col, cm){
17439 return !cm.isHidden(col) && cm.isCellEditable(col, row);
17443 onEditorKey : function(field, e){
17444 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
17449 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
17451 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
17453 }else if(k == e.ENTER && !e.ctrlKey){
17457 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
17459 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
17461 }else if(k == e.ESC){
17465 g.startEditing(newCell[0], newCell[1]);
17470 * Ext JS Library 1.1.1
17471 * Copyright(c) 2006-2007, Ext JS, LLC.
17473 * Originally Released Under LGPL - original licence link has changed is not relivant.
17476 * <script type="text/javascript">
17480 * @class Roo.bootstrap.PagingToolbar
17482 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
17484 * Create a new PagingToolbar
17485 * @param {Object} config The config object
17487 Roo.bootstrap.PagingToolbar = function(config)
17489 // old args format still supported... - xtype is prefered..
17490 // created from xtype...
17491 var ds = config.dataSource;
17493 if (config.items) {
17494 items = config.items;
17498 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
17505 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
17507 // supprot items array.
17509 Roo.each(items, function(e) {
17510 this.add(Roo.factory(e));
17519 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
17521 * @cfg {Roo.data.Store} dataSource
17522 * The underlying data store providing the paged data
17525 * @cfg {String/HTMLElement/Element} container
17526 * container The id or element that will contain the toolbar
17529 * @cfg {Boolean} displayInfo
17530 * True to display the displayMsg (defaults to false)
17533 * @cfg {Number} pageSize
17534 * The number of records to display per page (defaults to 20)
17538 * @cfg {String} displayMsg
17539 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
17541 displayMsg : 'Displaying {0} - {1} of {2}',
17543 * @cfg {String} emptyMsg
17544 * The message to display when no records are found (defaults to "No data to display")
17546 emptyMsg : 'No data to display',
17548 * Customizable piece of the default paging text (defaults to "Page")
17551 beforePageText : "Page",
17553 * Customizable piece of the default paging text (defaults to "of %0")
17556 afterPageText : "of {0}",
17558 * Customizable piece of the default paging text (defaults to "First Page")
17561 firstText : "First Page",
17563 * Customizable piece of the default paging text (defaults to "Previous Page")
17566 prevText : "Previous Page",
17568 * Customizable piece of the default paging text (defaults to "Next Page")
17571 nextText : "Next Page",
17573 * Customizable piece of the default paging text (defaults to "Last Page")
17576 lastText : "Last Page",
17578 * Customizable piece of the default paging text (defaults to "Refresh")
17581 refreshText : "Refresh",
17584 onRender : function(ct, position)
17586 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
17587 this.navgroup.parentId = this.id;
17588 this.navgroup.onRender(this.el, null);
17589 // add the buttons to the navgroup
17591 this.first = this.navgroup.addItem({
17592 tooltip: this.firstText,
17594 icon : 'fa fa-backward',
17596 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
17599 this.prev = this.navgroup.addItem({
17600 tooltip: this.prevText,
17602 icon : 'fa fa-step-backward',
17604 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
17606 //this.addSeparator();
17609 var field = this.navgroup.addItem( {
17611 cls : 'x-paging-position',
17613 html : this.beforePageText +
17614 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
17615 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
17618 this.field = field.el.select('input', true).first();
17619 this.field.on("keydown", this.onPagingKeydown, this);
17620 this.field.on("focus", function(){this.dom.select();});
17623 this.afterTextEl = field.el.select('.x-paging-after').first();
17624 //this.field.setHeight(18);
17625 //this.addSeparator();
17626 this.next = this.navgroup.addItem({
17627 tooltip: this.nextText,
17629 html : ' <i class="fa fa-step-forward">',
17631 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
17633 this.last = this.navgroup.addItem({
17634 tooltip: this.lastText,
17635 icon : 'fa fa-forward',
17638 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
17640 //this.addSeparator();
17641 this.loading = this.navgroup.addItem({
17642 tooltip: this.refreshText,
17643 icon: 'fa fa-refresh',
17645 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
17648 if(this.displayInfo){
17649 var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info' } );
17650 this.displayEl = navel.el.select('a',true).first();
17656 updateInfo : function(){
17657 if(this.displayEl){
17658 var count = this.ds.getCount();
17659 var msg = count == 0 ?
17663 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
17665 this.displayEl.update(msg);
17670 onLoad : function(ds, r, o){
17671 this.cursor = o.params ? o.params.start : 0;
17672 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
17674 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
17675 this.field.dom.value = ap;
17676 this.first.setDisabled(ap == 1);
17677 this.prev.setDisabled(ap == 1);
17678 this.next.setDisabled(ap == ps);
17679 this.last.setDisabled(ap == ps);
17680 this.loading.enable();
17685 getPageData : function(){
17686 var total = this.ds.getTotalCount();
17689 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
17690 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
17695 onLoadError : function(){
17696 this.loading.enable();
17700 onPagingKeydown : function(e){
17701 var k = e.getKey();
17702 var d = this.getPageData();
17704 var v = this.field.dom.value, pageNum;
17705 if(!v || isNaN(pageNum = parseInt(v, 10))){
17706 this.field.dom.value = d.activePage;
17709 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
17710 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
17713 else if(k == e.HOME || (k == e.UP && e.ctrlKey) || (k == e.PAGEUP && e.ctrlKey) || (k == e.RIGHT && e.ctrlKey) || k == e.END || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey))
17715 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
17716 this.field.dom.value = pageNum;
17717 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
17720 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
17722 var v = this.field.dom.value, pageNum;
17723 var increment = (e.shiftKey) ? 10 : 1;
17724 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
17726 if(!v || isNaN(pageNum = parseInt(v, 10))) {
17727 this.field.dom.value = d.activePage;
17730 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
17732 this.field.dom.value = parseInt(v, 10) + increment;
17733 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
17734 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
17741 beforeLoad : function(){
17743 this.loading.disable();
17748 onClick : function(which){
17755 ds.load({params:{start: 0, limit: this.pageSize}});
17758 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
17761 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
17764 var total = ds.getTotalCount();
17765 var extra = total % this.pageSize;
17766 var lastStart = extra ? (total - extra) : total-this.pageSize;
17767 ds.load({params:{start: lastStart, limit: this.pageSize}});
17770 ds.load({params:{start: this.cursor, limit: this.pageSize}});
17776 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
17777 * @param {Roo.data.Store} store The data store to unbind
17779 unbind : function(ds){
17780 ds.un("beforeload", this.beforeLoad, this);
17781 ds.un("load", this.onLoad, this);
17782 ds.un("loadexception", this.onLoadError, this);
17783 ds.un("remove", this.updateInfo, this);
17784 ds.un("add", this.updateInfo, this);
17785 this.ds = undefined;
17789 * Binds the paging toolbar to the specified {@link Roo.data.Store}
17790 * @param {Roo.data.Store} store The data store to bind
17792 bind : function(ds){
17793 ds.on("beforeload", this.beforeLoad, this);
17794 ds.on("load", this.onLoad, this);
17795 ds.on("loadexception", this.onLoadError, this);
17796 ds.on("remove", this.updateInfo, this);
17797 ds.on("add", this.updateInfo, this);
17808 * @class Roo.bootstrap.MessageBar
17809 * @extends Roo.bootstrap.Component
17810 * Bootstrap MessageBar class
17811 * @cfg {String} html contents of the MessageBar
17812 * @cfg {String} weight (info | success | warning | danger) default info
17813 * @cfg {String} beforeClass insert the bar before the given class
17814 * @cfg {Boolean} closable (true | false) default false
17815 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
17818 * Create a new Element
17819 * @param {Object} config The config object
17822 Roo.bootstrap.MessageBar = function(config){
17823 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
17826 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
17832 beforeClass: 'bootstrap-sticky-wrap',
17834 getAutoCreate : function(){
17838 cls: 'alert alert-dismissable alert-' + this.weight,
17843 html: this.html || ''
17849 cfg.cls += ' alert-messages-fixed';
17863 onRender : function(ct, position)
17865 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17868 var cfg = Roo.apply({}, this.getAutoCreate());
17872 cfg.cls += ' ' + this.cls;
17875 cfg.style = this.style;
17877 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
17879 this.el.setVisibilityMode(Roo.Element.DISPLAY);
17882 this.el.select('>button.close').on('click', this.hide, this);
17888 if (!this.rendered) {
17894 this.fireEvent('show', this);
17900 if (!this.rendered) {
17906 this.fireEvent('hide', this);
17909 update : function()
17911 // var e = this.el.dom.firstChild;
17913 // if(this.closable){
17914 // e = e.nextSibling;
17917 // e.data = this.html || '';
17919 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';