4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
21 * Do not use directly - it does not do anything..
22 * @param {Object} config The config object
27 Roo.bootstrap.Component = function(config){
28 Roo.bootstrap.Component.superclass.constructor.call(this, config);
31 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
34 allowDomMove : false, // to stop relocations in parent onRender...
42 initEvents : function() { },
48 can_build_overlaid : true,
55 // returns the parent component..
56 return Roo.ComponentMgr.get(this.parentId)
62 onRender : function(ct, position)
64 // Roo.log("Call onRender: " + this.xtype);
66 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
69 if (this.el.attr('xtype')) {
70 this.el.attr('xtypex', this.el.attr('xtype'));
71 this.el.dom.removeAttribute('xtype');
81 var cfg = Roo.apply({}, this.getAutoCreate());
84 // fill in the extra attributes
85 if (this.xattr && typeof(this.xattr) =='object') {
86 for (var i in this.xattr) {
87 cfg[i] = this.xattr[i];
92 cfg.dataId = this.dataId;
96 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
99 if (this.style) { // fixme needs to support more complex style data.
100 cfg.style = this.style;
104 cfg.name = this.name;
107 this.el = ct.createChild(cfg, position);
109 if(this.tabIndex !== undefined){
110 this.el.dom.setAttribute('tabIndex', this.tabIndex);
117 getChildContainer : function()
123 addxtype : function(tree,cntr)
127 cn = Roo.factory(tree);
129 cn.parentType = this.xtype; //??
130 cn.parentId = this.id;
132 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
134 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
136 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
138 var build_from_html = Roo.XComponent.build_from_html;
140 var is_body = (tree.xtype == 'Body') ;
142 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
144 var self_cntr_el = Roo.get(this[cntr]());
146 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
147 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
148 return this.addxtypeChild(tree,cntr);
151 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
154 return this.addxtypeChild(Roo.apply({}, tree),cntr);
157 Roo.log('skipping render');
165 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
171 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
175 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
180 addxtypeChild : function (tree, cntr)
182 Roo.log('addxtypeChild:' + cntr);
184 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
187 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
188 (typeof(tree['flexy:foreach']) != 'undefined');
193 // render the element if it's not BODY.
194 if (tree.xtype != 'Body') {
196 cn = Roo.factory(tree);
198 cn.parentType = this.xtype; //??
199 cn.parentId = this.id;
201 var build_from_html = Roo.XComponent.build_from_html;
204 // does the container contain child eleemnts with 'xtype' attributes.
205 // that match this xtype..
206 // note - when we render we create these as well..
207 // so we should check to see if body has xtype set.
208 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
210 var self_cntr_el = Roo.get(this[cntr]());
211 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
213 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
214 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
220 //echild.dom.removeAttribute('xtype');
222 Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
229 // if object has flexy:if - then it may or may not be rendered.
230 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
231 // skip a flexy if element.
232 Roo.log('skipping render');
235 // actually if flexy:foreach is found, we really want to create
236 // multiple copies here...
238 //Roo.log(this[cntr]());
239 cn.render(this[cntr]());
241 // then add the element..
248 if (typeof (tree.menu) != 'undefined') {
249 tree.menu.parentType = cn.xtype;
250 tree.menu.triggerEl = cn.el;
251 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
255 if (!tree.items || !tree.items.length) {
259 var items = tree.items;
262 //Roo.log(items.length);
264 for(var i =0;i < items.length;i++) {
265 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
286 * @class Roo.bootstrap.Body
287 * @extends Roo.bootstrap.Component
288 * Bootstrap Body class
292 * @param {Object} config The config object
295 Roo.bootstrap.Body = function(config){
296 Roo.bootstrap.Body.superclass.constructor.call(this, config);
297 this.el = Roo.get(document.body);
298 if (this.cls && this.cls.length) {
299 Roo.get(document.body).addClass(this.cls);
303 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
308 onRender : function(ct, position)
310 /* Roo.log("Roo.bootstrap.Body - onRender");
311 if (this.cls && this.cls.length) {
312 Roo.get(document.body).addClass(this.cls);
332 * @class Roo.bootstrap.ButtonGroup
333 * @extends Roo.bootstrap.Component
334 * Bootstrap ButtonGroup class
335 * @cfg {String} size lg | sm | xs (default empty normal)
336 * @cfg {String} align vertical | justified (default none)
337 * @cfg {String} direction up | down (default down)
338 * @cfg {Boolean} toolbar false | true
339 * @cfg {Boolean} btn true | false
344 * @param {Object} config The config object
347 Roo.bootstrap.ButtonGroup = function(config){
348 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
351 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
359 getAutoCreate : function(){
365 cfg.html = this.html || cfg.html;
376 if (['vertical','justified'].indexOf(this.align)!==-1) {
377 cfg.cls = 'btn-group-' + this.align;
379 if (this.align == 'justified') {
380 console.log(this.items);
384 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
385 cfg.cls += ' btn-group-' + this.size;
388 if (this.direction == 'up') {
389 cfg.cls += ' dropup' ;
405 * @class Roo.bootstrap.Button
406 * @extends Roo.bootstrap.Component
407 * Bootstrap Button class
408 * @cfg {String} html The button content
409 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger | link
410 * @cfg {String} size empty | lg | sm | xs
411 * @cfg {String} tag empty | a | input | submit
412 * @cfg {String} href empty or href
413 * @cfg {Boolean} disabled false | true
414 * @cfg {Boolean} isClose false | true
415 * @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
416 * @cfg {String} badge text for badge
417 * @cfg {String} theme default (or empty) | glow
418 * @cfg {Boolean} inverse false | true
419 * @cfg {Boolean} toggle false | true
420 * @cfg {String} ontext text for on toggle state
421 * @cfg {String} offtext text for off toggle state
422 * @cfg {Boolean} defaulton true | false
423 * @cfg {Boolean} preventDefault (true | false) default true
424 * @cfg {Boolean} removeClass true | false remove the standard class..
425 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
428 * Create a new button
429 * @param {Object} config The config object
433 Roo.bootstrap.Button = function(config){
434 Roo.bootstrap.Button.superclass.constructor.call(this, config);
439 * When a butotn is pressed
440 * @param {Roo.EventObject} e
445 * After the button has been toggles
446 * @param {Roo.EventObject} e
447 * @param {boolean} pressed (also available as button.pressed)
453 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
471 preventDefault: true,
480 getAutoCreate : function(){
488 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
489 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
494 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
496 if (this.toggle == true) {
499 cls: 'slider-frame roo-button',
504 'data-off-text':'OFF',
505 cls: 'slider-button',
511 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
512 cfg.cls += ' '+this.weight;
521 cfg["aria-hidden"] = true;
523 cfg.html = "×";
529 if (this.theme==='default') {
530 cfg.cls = 'btn roo-button';
532 //if (this.parentType != 'Navbar') {
533 this.weight = this.weight.length ? this.weight : 'default';
535 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
537 cfg.cls += ' btn-' + this.weight;
539 } else if (this.theme==='glow') {
542 cfg.cls = 'btn-glow roo-button';
544 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
546 cfg.cls += ' ' + this.weight;
552 this.cls += ' inverse';
557 cfg.cls += ' active';
561 cfg.disabled = 'disabled';
565 Roo.log('changing to ul' );
567 this.glyphicon = 'caret';
570 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
572 //gsRoo.log(this.parentType);
573 if (this.parentType === 'Navbar' && !this.parent().bar) {
574 Roo.log('changing to li?');
583 href : this.href || '#'
586 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
587 cfg.cls += ' dropdown';
594 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
596 if (this.glyphicon) {
597 cfg.html = ' ' + cfg.html;
602 cls: 'glyphicon glyphicon-' + this.glyphicon
612 // cfg.cls='btn roo-button';
616 var value = cfg.html;
621 cls: 'glyphicon glyphicon-' + this.glyphicon,
640 cfg.cls += ' dropdown';
641 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
644 if (cfg.tag !== 'a' && this.href !== '') {
645 throw "Tag must be a to set href.";
646 } else if (this.href.length > 0) {
647 cfg.href = this.href;
650 if(this.removeClass){
655 cfg.target = this.target;
660 initEvents: function() {
661 // Roo.log('init events?');
662 // Roo.log(this.el.dom);
663 if (this.el.hasClass('roo-button')) {
664 this.el.on('click', this.onClick, this);
666 this.el.select('.roo-button').on('click', this.onClick, this);
669 if(this.removeClass){
670 this.el.on('click', this.onClick, this);
673 this.el.enableDisplayMode();
676 onClick : function(e)
682 Roo.log('button on click ');
683 if(this.preventDefault){
686 if (this.pressed === true || this.pressed === false) {
687 this.pressed = !this.pressed;
688 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
689 this.fireEvent('toggle', this, e, this.pressed);
693 this.fireEvent('click', this, e);
697 * Enables this button
701 this.disabled = false;
702 this.el.removeClass('disabled');
706 * Disable this button
710 this.disabled = true;
711 this.el.addClass('disabled');
714 * sets the active state on/off,
715 * @param {Boolean} state (optional) Force a particular state
717 setActive : function(v) {
719 this.el[v ? 'addClass' : 'removeClass']('active');
722 * toggles the current active state
724 toggleActive : function()
726 var active = this.el.hasClass('active');
727 this.setActive(!active);
731 setText : function(str)
733 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
756 * @class Roo.bootstrap.Column
757 * @extends Roo.bootstrap.Component
758 * Bootstrap Column class
759 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
760 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
761 * @cfg {Number} md colspan out of 12 for computer-sized screens
762 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
763 * @cfg {String} html content of column.
766 * Create a new Column
767 * @param {Object} config The config object
770 Roo.bootstrap.Column = function(config){
771 Roo.bootstrap.Column.superclass.constructor.call(this, config);
774 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
783 getAutoCreate : function(){
784 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
792 ['xs','sm','md','lg'].map(function(size){
793 if (settings[size]) {
794 cfg.cls += ' col-' + size + '-' + settings[size];
797 if (this.html.length) {
798 cfg.html = this.html;
817 * @class Roo.bootstrap.Container
818 * @extends Roo.bootstrap.Component
819 * Bootstrap Container class
820 * @cfg {Boolean} jumbotron is it a jumbotron element
821 * @cfg {String} html content of element
822 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
823 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
824 * @cfg {String} header content of header (for panel)
825 * @cfg {String} footer content of footer (for panel)
826 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
827 * @cfg {String} tag (header|aside|section) type of HTML tag.
831 * Create a new Container
832 * @param {Object} config The config object
835 Roo.bootstrap.Container = function(config){
836 Roo.bootstrap.Container.superclass.constructor.call(this, config);
839 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
850 getChildContainer : function() {
856 if (this.panel.length) {
857 return this.el.select('.panel-body',true).first();
864 getAutoCreate : function(){
867 tag : this.tag || 'div',
871 if (this.jumbotron) {
872 cfg.cls = 'jumbotron';
874 // - this is applied by the parent..
876 // cfg.cls = this.cls + '';
879 if (this.sticky.length) {
881 var bd = Roo.get(document.body);
882 if (!bd.hasClass('bootstrap-sticky')) {
883 bd.addClass('bootstrap-sticky');
884 Roo.select('html',true).setStyle('height', '100%');
887 cfg.cls += 'bootstrap-sticky-' + this.sticky;
891 if (this.well.length) {
895 cfg.cls +=' well well-' +this.well;
905 if (this.panel.length) {
906 cfg.cls += ' panel panel-' + this.panel;
908 if (this.header.length) {
911 cls : 'panel-heading',
927 if (this.footer.length) {
929 cls : 'panel-footer',
938 body.html = this.html || cfg.html;
940 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
941 cfg.cls = 'container';
958 * @class Roo.bootstrap.Img
959 * @extends Roo.bootstrap.Component
960 * Bootstrap Img class
961 * @cfg {Boolean} imgResponsive false | true
962 * @cfg {String} border rounded | circle | thumbnail
963 * @cfg {String} src image source
964 * @cfg {String} alt image alternative text
965 * @cfg {String} href a tag href
966 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
970 * @param {Object} config The config object
973 Roo.bootstrap.Img = function(config){
974 Roo.bootstrap.Img.superclass.constructor.call(this, config);
980 * The img click event for the img.
981 * @param {Roo.EventObject} e
987 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
995 getAutoCreate : function(){
999 cls: (this.imgResponsive) ? 'img-responsive' : '',
1003 cfg.html = this.html || cfg.html;
1005 cfg.src = this.src || cfg.src;
1007 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1008 cfg.cls += ' img-' + this.border;
1025 a.target = this.target;
1031 return (this.href) ? a : cfg;
1034 initEvents: function() {
1037 this.el.on('click', this.onClick, this);
1041 onClick : function(e)
1043 Roo.log('img onclick');
1044 this.fireEvent('click', this, e);
1058 * @class Roo.bootstrap.Link
1059 * @extends Roo.bootstrap.Component
1060 * Bootstrap Link Class
1061 * @cfg {String} alt image alternative text
1062 * @cfg {String} href a tag href
1063 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1064 * @cfg {String} html the content of the link.
1068 * Create a new Input
1069 * @param {Object} config The config object
1072 Roo.bootstrap.Link = function(config){
1073 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1079 * The img click event for the img.
1080 * @param {Roo.EventObject} e
1086 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1091 getAutoCreate : function(){
1095 html : this.html || 'html-missing'
1102 cfg.href = this.href || '#';
1104 cfg.target = this.target;
1110 initEvents: function() {
1113 this.el.on('click', this.onClick, this);
1117 onClick : function(e)
1119 //Roo.log('img onclick');
1120 this.fireEvent('click', this, e);
1133 * @class Roo.bootstrap.Header
1134 * @extends Roo.bootstrap.Component
1135 * Bootstrap Header class
1136 * @cfg {String} html content of header
1137 * @cfg {Number} level (1|2|3|4|5|6) default 1
1140 * Create a new Header
1141 * @param {Object} config The config object
1145 Roo.bootstrap.Header = function(config){
1146 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1149 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1157 getAutoCreate : function(){
1160 tag: 'h' + (1 *this.level),
1161 html: this.html || 'fill in html'
1173 * Ext JS Library 1.1.1
1174 * Copyright(c) 2006-2007, Ext JS, LLC.
1176 * Originally Released Under LGPL - original licence link has changed is not relivant.
1179 * <script type="text/javascript">
1183 * @class Roo.bootstrap.MenuMgr
1184 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1187 Roo.bootstrap.MenuMgr = function(){
1188 var menus, active, groups = {}, attached = false, lastShow = new Date();
1190 // private - called when first menu is created
1193 active = new Roo.util.MixedCollection();
1194 Roo.get(document).addKeyListener(27, function(){
1195 if(active.length > 0){
1203 if(active && active.length > 0){
1204 var c = active.clone();
1214 if(active.length < 1){
1215 Roo.get(document).un("mouseup", onMouseDown);
1223 var last = active.last();
1224 lastShow = new Date();
1227 Roo.get(document).on("mouseup", onMouseDown);
1232 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1233 m.parentMenu.activeChild = m;
1234 }else if(last && last.isVisible()){
1235 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1240 function onBeforeHide(m){
1242 m.activeChild.hide();
1244 if(m.autoHideTimer){
1245 clearTimeout(m.autoHideTimer);
1246 delete m.autoHideTimer;
1251 function onBeforeShow(m){
1252 var pm = m.parentMenu;
1253 if(!pm && !m.allowOtherMenus){
1255 }else if(pm && pm.activeChild && active != m){
1256 pm.activeChild.hide();
1261 function onMouseDown(e){
1262 Roo.log("on MouseDown");
1263 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1271 function onBeforeCheck(mi, state){
1273 var g = groups[mi.group];
1274 for(var i = 0, l = g.length; i < l; i++){
1276 g[i].setChecked(false);
1285 * Hides all menus that are currently visible
1287 hideAll : function(){
1292 register : function(menu){
1296 menus[menu.id] = menu;
1297 menu.on("beforehide", onBeforeHide);
1298 menu.on("hide", onHide);
1299 menu.on("beforeshow", onBeforeShow);
1300 menu.on("show", onShow);
1302 if(g && menu.events["checkchange"]){
1306 groups[g].push(menu);
1307 menu.on("checkchange", onCheck);
1312 * Returns a {@link Roo.menu.Menu} object
1313 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1314 * be used to generate and return a new Menu instance.
1316 get : function(menu){
1317 if(typeof menu == "string"){ // menu id
1319 }else if(menu.events){ // menu instance
1322 /*else if(typeof menu.length == 'number'){ // array of menu items?
1323 return new Roo.bootstrap.Menu({items:menu});
1324 }else{ // otherwise, must be a config
1325 return new Roo.bootstrap.Menu(menu);
1332 unregister : function(menu){
1333 delete menus[menu.id];
1334 menu.un("beforehide", onBeforeHide);
1335 menu.un("hide", onHide);
1336 menu.un("beforeshow", onBeforeShow);
1337 menu.un("show", onShow);
1339 if(g && menu.events["checkchange"]){
1340 groups[g].remove(menu);
1341 menu.un("checkchange", onCheck);
1346 registerCheckable : function(menuItem){
1347 var g = menuItem.group;
1352 groups[g].push(menuItem);
1353 menuItem.on("beforecheckchange", onBeforeCheck);
1358 unregisterCheckable : function(menuItem){
1359 var g = menuItem.group;
1361 groups[g].remove(menuItem);
1362 menuItem.un("beforecheckchange", onBeforeCheck);
1374 * @class Roo.bootstrap.Menu
1375 * @extends Roo.bootstrap.Component
1376 * Bootstrap Menu class - container for MenuItems
1377 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1381 * @param {Object} config The config object
1385 Roo.bootstrap.Menu = function(config){
1386 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1387 if (this.registerMenu) {
1388 Roo.bootstrap.MenuMgr.register(this);
1393 * Fires before this menu is displayed
1394 * @param {Roo.menu.Menu} this
1399 * Fires before this menu is hidden
1400 * @param {Roo.menu.Menu} this
1405 * Fires after this menu is displayed
1406 * @param {Roo.menu.Menu} this
1411 * Fires after this menu is hidden
1412 * @param {Roo.menu.Menu} this
1417 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1418 * @param {Roo.menu.Menu} this
1419 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1420 * @param {Roo.EventObject} e
1425 * Fires when the mouse is hovering over this menu
1426 * @param {Roo.menu.Menu} this
1427 * @param {Roo.EventObject} e
1428 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1433 * Fires when the mouse exits this menu
1434 * @param {Roo.menu.Menu} this
1435 * @param {Roo.EventObject} e
1436 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1441 * Fires when a menu item contained in this menu is clicked
1442 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1443 * @param {Roo.EventObject} e
1447 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1450 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1454 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1457 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1459 registerMenu : true,
1461 menuItems :false, // stores the menu items..
1467 getChildContainer : function() {
1471 getAutoCreate : function(){
1473 //if (['right'].indexOf(this.align)!==-1) {
1474 // cfg.cn[1].cls += ' pull-right'
1480 cls : 'dropdown-menu' ,
1481 style : 'z-index:1000'
1485 if (this.type === 'submenu') {
1486 cfg.cls = 'submenu active';
1488 if (this.type === 'treeview') {
1489 cfg.cls = 'treeview-menu';
1494 initEvents : function() {
1496 // Roo.log("ADD event");
1497 // Roo.log(this.triggerEl.dom);
1498 this.triggerEl.on('click', this.onTriggerPress, this);
1499 this.triggerEl.addClass('dropdown-toggle');
1500 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1502 this.el.on("mouseover", this.onMouseOver, this);
1503 this.el.on("mouseout", this.onMouseOut, this);
1507 findTargetItem : function(e){
1508 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1512 //Roo.log(t); Roo.log(t.id);
1514 //Roo.log(this.menuitems);
1515 return this.menuitems.get(t.id);
1517 //return this.items.get(t.menuItemId);
1522 onClick : function(e){
1523 Roo.log("menu.onClick");
1524 var t = this.findTargetItem(e);
1530 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1531 if(t == this.activeItem && t.shouldDeactivate(e)){
1532 this.activeItem.deactivate();
1533 delete this.activeItem;
1537 this.setActiveItem(t, true);
1544 Roo.log('pass click event');
1548 this.fireEvent("click", this, t, e);
1552 onMouseOver : function(e){
1553 var t = this.findTargetItem(e);
1556 // if(t.canActivate && !t.disabled){
1557 // this.setActiveItem(t, true);
1561 this.fireEvent("mouseover", this, e, t);
1563 isVisible : function(){
1564 return !this.hidden;
1566 onMouseOut : function(e){
1567 var t = this.findTargetItem(e);
1570 // if(t == this.activeItem && t.shouldDeactivate(e)){
1571 // this.activeItem.deactivate();
1572 // delete this.activeItem;
1575 this.fireEvent("mouseout", this, e, t);
1580 * Displays this menu relative to another element
1581 * @param {String/HTMLElement/Roo.Element} element The element to align to
1582 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1583 * the element (defaults to this.defaultAlign)
1584 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1586 show : function(el, pos, parentMenu){
1587 this.parentMenu = parentMenu;
1591 this.fireEvent("beforeshow", this);
1592 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1595 * Displays this menu at a specific xy position
1596 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1597 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1599 showAt : function(xy, parentMenu, /* private: */_e){
1600 this.parentMenu = parentMenu;
1605 this.fireEvent("beforeshow", this);
1607 //xy = this.el.adjustForConstraints(xy);
1609 //this.el.setXY(xy);
1611 this.hideMenuItems();
1612 this.hidden = false;
1613 this.triggerEl.addClass('open');
1615 this.fireEvent("show", this);
1621 this.doFocus.defer(50, this);
1625 doFocus : function(){
1627 this.focusEl.focus();
1632 * Hides this menu and optionally all parent menus
1633 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1635 hide : function(deep){
1637 this.hideMenuItems();
1638 if(this.el && this.isVisible()){
1639 this.fireEvent("beforehide", this);
1640 if(this.activeItem){
1641 this.activeItem.deactivate();
1642 this.activeItem = null;
1644 this.triggerEl.removeClass('open');;
1646 this.fireEvent("hide", this);
1648 if(deep === true && this.parentMenu){
1649 this.parentMenu.hide(true);
1653 onTriggerPress : function(e)
1656 Roo.log('trigger press');
1657 //Roo.log(e.getTarget());
1658 // Roo.log(this.triggerEl.dom);
1659 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1662 if (this.isVisible()) {
1666 this.show(this.triggerEl, false, false);
1675 hideMenuItems : function()
1677 //$(backdrop).remove()
1678 Roo.select('.open',true).each(function(aa) {
1680 aa.removeClass('open');
1681 //var parent = getParent($(this))
1682 //var relatedTarget = { relatedTarget: this }
1684 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1685 //if (e.isDefaultPrevented()) return
1686 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1689 addxtypeChild : function (tree, cntr) {
1690 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1692 this.menuitems.add(comp);
1713 * @class Roo.bootstrap.MenuItem
1714 * @extends Roo.bootstrap.Component
1715 * Bootstrap MenuItem class
1716 * @cfg {String} html the menu label
1717 * @cfg {String} href the link
1718 * @cfg {Boolean} preventDefault (true | false) default true
1722 * Create a new MenuItem
1723 * @param {Object} config The config object
1727 Roo.bootstrap.MenuItem = function(config){
1728 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1733 * The raw click event for the entire grid.
1734 * @param {Roo.EventObject} e
1740 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1744 preventDefault: true,
1746 getAutoCreate : function(){
1749 cls: 'dropdown-menu-item',
1758 if (this.parent().type == 'treeview') {
1759 cfg.cls = 'treeview-menu';
1762 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1763 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1767 initEvents: function() {
1769 //this.el.select('a').on('click', this.onClick, this);
1772 onClick : function(e)
1774 Roo.log('item on click ');
1775 //if(this.preventDefault){
1776 // e.preventDefault();
1778 //this.parent().hideMenuItems();
1780 this.fireEvent('click', this, e);
1799 * @class Roo.bootstrap.MenuSeparator
1800 * @extends Roo.bootstrap.Component
1801 * Bootstrap MenuSeparator class
1804 * Create a new MenuItem
1805 * @param {Object} config The config object
1809 Roo.bootstrap.MenuSeparator = function(config){
1810 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1813 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1815 getAutoCreate : function(){
1830 <div class="modal fade">
1831 <div class="modal-dialog">
1832 <div class="modal-content">
1833 <div class="modal-header">
1834 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1835 <h4 class="modal-title">Modal title</h4>
1837 <div class="modal-body">
1838 <p>One fine body…</p>
1840 <div class="modal-footer">
1841 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1842 <button type="button" class="btn btn-primary">Save changes</button>
1844 </div><!-- /.modal-content -->
1845 </div><!-- /.modal-dialog -->
1846 </div><!-- /.modal -->
1856 * @class Roo.bootstrap.Modal
1857 * @extends Roo.bootstrap.Component
1858 * Bootstrap Modal class
1859 * @cfg {String} title Title of dialog
1860 * @cfg {Boolean} specificTitle (true|false) default false
1861 * @cfg {Array} buttons Array of buttons or standard button set..
1862 * @cfg {String} buttonPosition (left|right|center) default right
1865 * Create a new Modal Dialog
1866 * @param {Object} config The config object
1869 Roo.bootstrap.Modal = function(config){
1870 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1875 * The raw btnclick event for the button
1876 * @param {Roo.EventObject} e
1880 this.buttons = this.buttons || [];
1883 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1885 title : 'test dialog',
1892 specificTitle: false,
1894 buttonPosition: 'right',
1896 onRender : function(ct, position)
1898 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1901 var cfg = Roo.apply({}, this.getAutoCreate());
1904 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1906 //if (!cfg.name.length) {
1910 cfg.cls += ' ' + this.cls;
1913 cfg.style = this.style;
1915 this.el = Roo.get(document.body).createChild(cfg, position);
1917 //var type = this.el.dom.type;
1919 if(this.tabIndex !== undefined){
1920 this.el.dom.setAttribute('tabIndex', this.tabIndex);
1925 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1926 this.maskEl.enableDisplayMode("block");
1928 //this.el.addClass("x-dlg-modal");
1930 if (this.buttons.length) {
1931 Roo.each(this.buttons, function(bb) {
1932 b = Roo.apply({}, bb);
1933 b.xns = b.xns || Roo.bootstrap;
1934 b.xtype = b.xtype || 'Button';
1935 if (typeof(b.listeners) == 'undefined') {
1936 b.listeners = { click : this.onButtonClick.createDelegate(this) };
1939 var btn = Roo.factory(b);
1941 btn.onRender(this.el.select('.modal-footer div').first());
1945 // render the children.
1948 if(typeof(this.items) != 'undefined'){
1949 var items = this.items;
1952 for(var i =0;i < items.length;i++) {
1953 nitems.push(this.addxtype(Roo.apply({}, items[i])));
1957 this.items = nitems;
1959 this.body = this.el.select('.modal-body',true).first();
1960 this.close = this.el.select('.modal-header .close', true).first();
1961 this.footer = this.el.select('.modal-footer',true).first();
1963 //this.el.addClass([this.fieldClass, this.cls]);
1966 getAutoCreate : function(){
1971 html : this.html || ''
1976 cls : 'modal-title',
1980 if(this.specificTitle){
1986 style : 'display: none',
1989 cls: "modal-dialog",
1992 cls : "modal-content",
1995 cls : 'modal-header',
2007 cls : 'modal-footer',
2011 cls: 'btn-' + this.buttonPosition
2030 getChildContainer : function() {
2032 return this.el.select('.modal-body',true).first();
2035 getButtonContainer : function() {
2036 return this.el.select('.modal-footer div',true).first();
2039 initEvents : function()
2041 this.el.select('.modal-header .close').on('click', this.hide, this);
2043 // this.addxtype(this);
2047 if (!this.rendered) {
2051 this.el.addClass('on');
2052 this.el.removeClass('fade');
2053 this.el.setStyle('display', 'block');
2054 Roo.get(document.body).addClass("x-body-masked");
2055 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2057 this.el.setStyle('zIndex', '10001');
2058 this.fireEvent('show', this);
2064 Roo.log('Modal hide?!');
2066 Roo.get(document.body).removeClass("x-body-masked");
2067 this.el.removeClass('on');
2068 this.el.addClass('fade');
2069 this.el.setStyle('display', 'none');
2070 this.fireEvent('hide', this);
2073 addButton : function(str, cb)
2077 var b = Roo.apply({}, { html : str } );
2078 b.xns = b.xns || Roo.bootstrap;
2079 b.xtype = b.xtype || 'Button';
2080 if (typeof(b.listeners) == 'undefined') {
2081 b.listeners = { click : cb.createDelegate(this) };
2084 var btn = Roo.factory(b);
2086 btn.onRender(this.el.select('.modal-footer div').first());
2092 setDefaultButton : function(btn)
2094 //this.el.select('.modal-footer').()
2096 resizeTo: function(w,h)
2100 setContentSize : function(w, h)
2104 onButtonClick: function(btn,e)
2107 this.fireEvent('btnclick', btn.name, e);
2109 setTitle: function(str) {
2110 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2116 Roo.apply(Roo.bootstrap.Modal, {
2118 * Button config that displays a single OK button
2127 * Button config that displays Yes and No buttons
2143 * Button config that displays OK and Cancel buttons
2158 * Button config that displays Yes, No and Cancel buttons
2180 * messagebox - can be used as a replace
2184 * @class Roo.MessageBox
2185 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2189 Roo.Msg.alert('Status', 'Changes saved successfully.');
2191 // Prompt for user data:
2192 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2194 // process text value...
2198 // Show a dialog using config options:
2200 title:'Save Changes?',
2201 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2202 buttons: Roo.Msg.YESNOCANCEL,
2209 Roo.bootstrap.MessageBox = function(){
2210 var dlg, opt, mask, waitTimer;
2211 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2212 var buttons, activeTextEl, bwidth;
2216 var handleButton = function(button){
2218 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2222 var handleHide = function(){
2224 dlg.el.removeClass(opt.cls);
2227 // Roo.TaskMgr.stop(waitTimer);
2228 // waitTimer = null;
2233 var updateButtons = function(b){
2236 buttons["ok"].hide();
2237 buttons["cancel"].hide();
2238 buttons["yes"].hide();
2239 buttons["no"].hide();
2240 //dlg.footer.dom.style.display = 'none';
2243 dlg.footer.dom.style.display = '';
2244 for(var k in buttons){
2245 if(typeof buttons[k] != "function"){
2248 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2249 width += buttons[k].el.getWidth()+15;
2259 var handleEsc = function(d, k, e){
2260 if(opt && opt.closable !== false){
2270 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2271 * @return {Roo.BasicDialog} The BasicDialog element
2273 getDialog : function(){
2275 dlg = new Roo.bootstrap.Modal( {
2278 //constraintoviewport:false,
2280 //collapsible : false,
2285 //buttonAlign:"center",
2286 closeClick : function(){
2287 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2290 handleButton("cancel");
2295 dlg.on("hide", handleHide);
2297 //dlg.addKeyListener(27, handleEsc);
2299 this.buttons = buttons;
2300 var bt = this.buttonText;
2301 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2302 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2303 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2304 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2306 bodyEl = dlg.body.createChild({
2308 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2309 '<textarea class="roo-mb-textarea"></textarea>' +
2310 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2312 msgEl = bodyEl.dom.firstChild;
2313 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2314 textboxEl.enableDisplayMode();
2315 textboxEl.addKeyListener([10,13], function(){
2316 if(dlg.isVisible() && opt && opt.buttons){
2319 }else if(opt.buttons.yes){
2320 handleButton("yes");
2324 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2325 textareaEl.enableDisplayMode();
2326 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2327 progressEl.enableDisplayMode();
2328 var pf = progressEl.dom.firstChild;
2330 pp = Roo.get(pf.firstChild);
2331 pp.setHeight(pf.offsetHeight);
2339 * Updates the message box body text
2340 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2341 * the XHTML-compliant non-breaking space character '&#160;')
2342 * @return {Roo.MessageBox} This message box
2344 updateText : function(text){
2345 if(!dlg.isVisible() && !opt.width){
2346 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2348 msgEl.innerHTML = text || ' ';
2350 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2351 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2353 Math.min(opt.width || cw , this.maxWidth),
2354 Math.max(opt.minWidth || this.minWidth, bwidth)
2357 activeTextEl.setWidth(w);
2359 if(dlg.isVisible()){
2360 dlg.fixedcenter = false;
2362 // to big, make it scroll. = But as usual stupid IE does not support
2365 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2366 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2367 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2369 bodyEl.dom.style.height = '';
2370 bodyEl.dom.style.overflowY = '';
2373 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2375 bodyEl.dom.style.overflowX = '';
2378 dlg.setContentSize(w, bodyEl.getHeight());
2379 if(dlg.isVisible()){
2380 dlg.fixedcenter = true;
2386 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2387 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2388 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2389 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2390 * @return {Roo.MessageBox} This message box
2392 updateProgress : function(value, text){
2394 this.updateText(text);
2396 if (pp) { // weird bug on my firefox - for some reason this is not defined
2397 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2403 * Returns true if the message box is currently displayed
2404 * @return {Boolean} True if the message box is visible, else false
2406 isVisible : function(){
2407 return dlg && dlg.isVisible();
2411 * Hides the message box if it is displayed
2414 if(this.isVisible()){
2420 * Displays a new message box, or reinitializes an existing message box, based on the config options
2421 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2422 * The following config object properties are supported:
2424 Property Type Description
2425 ---------- --------------- ------------------------------------------------------------------------------------
2426 animEl String/Element An id or Element from which the message box should animate as it opens and
2427 closes (defaults to undefined)
2428 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2429 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2430 closable Boolean False to hide the top-right close button (defaults to true). Note that
2431 progress and wait dialogs will ignore this property and always hide the
2432 close button as they can only be closed programmatically.
2433 cls String A custom CSS class to apply to the message box element
2434 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2435 displayed (defaults to 75)
2436 fn Function A callback function to execute after closing the dialog. The arguments to the
2437 function will be btn (the name of the button that was clicked, if applicable,
2438 e.g. "ok"), and text (the value of the active text field, if applicable).
2439 Progress and wait dialogs will ignore this option since they do not respond to
2440 user actions and can only be closed programmatically, so any required function
2441 should be called by the same code after it closes the dialog.
2442 icon String A CSS class that provides a background image to be used as an icon for
2443 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2444 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2445 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2446 modal Boolean False to allow user interaction with the page while the message box is
2447 displayed (defaults to true)
2448 msg String A string that will replace the existing message box body text (defaults
2449 to the XHTML-compliant non-breaking space character ' ')
2450 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2451 progress Boolean True to display a progress bar (defaults to false)
2452 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2453 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2454 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2455 title String The title text
2456 value String The string value to set into the active textbox element if displayed
2457 wait Boolean True to display a progress bar (defaults to false)
2458 width Number The width of the dialog in pixels
2465 msg: 'Please enter your address:',
2467 buttons: Roo.MessageBox.OKCANCEL,
2470 animEl: 'addAddressBtn'
2473 * @param {Object} config Configuration options
2474 * @return {Roo.MessageBox} This message box
2476 show : function(options)
2479 // this causes nightmares if you show one dialog after another
2480 // especially on callbacks..
2482 if(this.isVisible()){
2485 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2486 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2487 Roo.log("New Dialog Message:" + options.msg )
2488 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2489 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2492 var d = this.getDialog();
2494 d.setTitle(opt.title || " ");
2495 d.close.setDisplayed(opt.closable !== false);
2496 activeTextEl = textboxEl;
2497 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2502 textareaEl.setHeight(typeof opt.multiline == "number" ?
2503 opt.multiline : this.defaultTextHeight);
2504 activeTextEl = textareaEl;
2513 progressEl.setDisplayed(opt.progress === true);
2514 this.updateProgress(0);
2515 activeTextEl.dom.value = opt.value || "";
2517 dlg.setDefaultButton(activeTextEl);
2519 var bs = opt.buttons;
2523 }else if(bs && bs.yes){
2524 db = buttons["yes"];
2526 dlg.setDefaultButton(db);
2528 bwidth = updateButtons(opt.buttons);
2529 this.updateText(opt.msg);
2531 d.el.addClass(opt.cls);
2533 d.proxyDrag = opt.proxyDrag === true;
2534 d.modal = opt.modal !== false;
2535 d.mask = opt.modal !== false ? mask : false;
2537 // force it to the end of the z-index stack so it gets a cursor in FF
2538 document.body.appendChild(dlg.el.dom);
2539 d.animateTarget = null;
2540 d.show(options.animEl);
2546 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2547 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2548 * and closing the message box when the process is complete.
2549 * @param {String} title The title bar text
2550 * @param {String} msg The message box body text
2551 * @return {Roo.MessageBox} This message box
2553 progress : function(title, msg){
2560 minWidth: this.minProgressWidth,
2567 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2568 * If a callback function is passed it will be called after the user clicks the button, and the
2569 * id of the button that was clicked will be passed as the only parameter to the callback
2570 * (could also be the top-right close button).
2571 * @param {String} title The title bar text
2572 * @param {String} msg The message box body text
2573 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2574 * @param {Object} scope (optional) The scope of the callback function
2575 * @return {Roo.MessageBox} This message box
2577 alert : function(title, msg, fn, scope){
2590 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2591 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2592 * You are responsible for closing the message box when the process is complete.
2593 * @param {String} msg The message box body text
2594 * @param {String} title (optional) The title bar text
2595 * @return {Roo.MessageBox} This message box
2597 wait : function(msg, title){
2608 waitTimer = Roo.TaskMgr.start({
2610 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2618 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2619 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2620 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2621 * @param {String} title The title bar text
2622 * @param {String} msg The message box body text
2623 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2624 * @param {Object} scope (optional) The scope of the callback function
2625 * @return {Roo.MessageBox} This message box
2627 confirm : function(title, msg, fn, scope){
2631 buttons: this.YESNO,
2640 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2641 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2642 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2643 * (could also be the top-right close button) and the text that was entered will be passed as the two
2644 * parameters to the callback.
2645 * @param {String} title The title bar text
2646 * @param {String} msg The message box body text
2647 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2648 * @param {Object} scope (optional) The scope of the callback function
2649 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2650 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2651 * @return {Roo.MessageBox} This message box
2653 prompt : function(title, msg, fn, scope, multiline){
2657 buttons: this.OKCANCEL,
2662 multiline: multiline,
2669 * Button config that displays a single OK button
2674 * Button config that displays Yes and No buttons
2677 YESNO : {yes:true, no:true},
2679 * Button config that displays OK and Cancel buttons
2682 OKCANCEL : {ok:true, cancel:true},
2684 * Button config that displays Yes, No and Cancel buttons
2687 YESNOCANCEL : {yes:true, no:true, cancel:true},
2690 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2693 defaultTextHeight : 75,
2695 * The maximum width in pixels of the message box (defaults to 600)
2700 * The minimum width in pixels of the message box (defaults to 100)
2705 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2706 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2709 minProgressWidth : 250,
2711 * An object containing the default button text strings that can be overriden for localized language support.
2712 * Supported properties are: ok, cancel, yes and no.
2713 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2726 * Shorthand for {@link Roo.MessageBox}
2728 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2729 Roo.Msg = Roo.Msg || Roo.MessageBox;
2738 * @class Roo.bootstrap.Navbar
2739 * @extends Roo.bootstrap.Component
2740 * Bootstrap Navbar class
2743 * Create a new Navbar
2744 * @param {Object} config The config object
2748 Roo.bootstrap.Navbar = function(config){
2749 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2753 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2762 getAutoCreate : function(){
2765 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
2769 initEvents :function ()
2771 //Roo.log(this.el.select('.navbar-toggle',true));
2772 this.el.select('.navbar-toggle',true).on('click', function() {
2773 // Roo.log('click');
2774 this.el.select('.navbar-collapse',true).toggleClass('in');
2782 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2784 var size = this.el.getSize();
2785 this.maskEl.setSize(size.width, size.height);
2786 this.maskEl.enableDisplayMode("block");
2795 getChildContainer : function()
2797 if (this.el.select('.collapse').getCount()) {
2798 return this.el.select('.collapse',true).first();
2830 * @class Roo.bootstrap.NavSimplebar
2831 * @extends Roo.bootstrap.Navbar
2832 * Bootstrap Sidebar class
2834 * @cfg {Boolean} inverse is inverted color
2836 * @cfg {String} type (nav | pills | tabs)
2837 * @cfg {Boolean} arrangement stacked | justified
2838 * @cfg {String} align (left | right) alignment
2840 * @cfg {Boolean} main (true|false) main nav bar? default false
2841 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
2843 * @cfg {String} tag (header|footer|nav|div) default is nav
2849 * Create a new Sidebar
2850 * @param {Object} config The config object
2854 Roo.bootstrap.NavSimplebar = function(config){
2855 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
2858 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
2874 getAutoCreate : function(){
2878 tag : this.tag || 'div',
2891 this.type = this.type || 'nav';
2892 if (['tabs','pills'].indexOf(this.type)!==-1) {
2893 cfg.cn[0].cls += ' nav-' + this.type
2897 if (this.type!=='nav') {
2898 Roo.log('nav type must be nav/tabs/pills')
2900 cfg.cn[0].cls += ' navbar-nav'
2906 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
2907 cfg.cn[0].cls += ' nav-' + this.arrangement;
2911 if (this.align === 'right') {
2912 cfg.cn[0].cls += ' navbar-right';
2916 cfg.cls += ' navbar-inverse';
2943 * @class Roo.bootstrap.NavHeaderbar
2944 * @extends Roo.bootstrap.NavSimplebar
2945 * Bootstrap Sidebar class
2947 * @cfg {String} brand what is brand
2948 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
2949 * @cfg {String} brand_href href of the brand
2952 * Create a new Sidebar
2953 * @param {Object} config The config object
2957 Roo.bootstrap.NavHeaderbar = function(config){
2958 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
2961 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
2968 getAutoCreate : function(){
2973 tag: this.nav || 'nav',
2979 cls: 'navbar-header',
2984 cls: 'navbar-toggle',
2985 'data-toggle': 'collapse',
2990 html: 'Toggle navigation'
3010 cls: 'collapse navbar-collapse'
3015 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3017 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3018 cfg.cls += ' navbar-' + this.position;
3020 // tag can override this..
3022 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3025 if (this.brand !== '') {
3028 href: this.brand_href ? this.brand_href : '#',
3029 cls: 'navbar-brand',
3037 cfg.cls += ' main-nav';
3062 * @class Roo.bootstrap.NavSidebar
3063 * @extends Roo.bootstrap.Navbar
3064 * Bootstrap Sidebar class
3067 * Create a new Sidebar
3068 * @param {Object} config The config object
3072 Roo.bootstrap.NavSidebar = function(config){
3073 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3076 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3078 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3080 getAutoCreate : function(){
3085 cls: 'sidebar sidebar-nav'
3107 * @class Roo.bootstrap.NavGroup
3108 * @extends Roo.bootstrap.Component
3109 * Bootstrap NavGroup class
3110 * @cfg {String} align left | right
3111 * @cfg {Boolean} inverse false | true
3112 * @cfg {String} type (nav|pills|tab) default nav
3113 * @cfg {String} navId - reference Id for navbar.
3117 * Create a new nav group
3118 * @param {Object} config The config object
3121 Roo.bootstrap.NavGroup = function(config){
3122 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3124 Roo.bootstrap.NavGroup.register(this);
3128 * Fires when the active item changes
3129 * @param {Roo.bootstrap.NavGroup} this
3130 * @param {Roo.bootstrap.Navbar.Item} item The item selected
3131 * @param {Roo.bootstrap.Navbar.Item} item The previously selected item
3138 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3149 getAutoCreate : function()
3151 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3158 if (['tabs','pills'].indexOf(this.type)!==-1) {
3159 cfg.cls += ' nav-' + this.type
3161 if (this.type!=='nav') {
3162 Roo.log('nav type must be nav/tabs/pills')
3164 cfg.cls += ' navbar-nav'
3167 if (this.parent().sidebar) {
3170 cls: 'dashboard-menu sidebar-menu'
3176 if (this.form === true) {
3182 if (this.align === 'right') {
3183 cfg.cls += ' navbar-right';
3185 cfg.cls += ' navbar-left';
3189 if (this.align === 'right') {
3190 cfg.cls += ' navbar-right';
3194 cfg.cls += ' navbar-inverse';
3202 setActiveItem : function(item)
3205 Roo.each(this.navItems, function(v){
3210 v.setActive(false, true);
3217 item.setActive(true, true);
3218 this.fireEvent('changed', this, item, prev);
3224 register : function(item)
3226 this.navItems.push( item);
3227 item.navId = this.navId;
3230 getNavItem: function(tabId)
3233 Roo.each(this.navItems, function(e) {
3234 if (e.tabId == tabId) {
3246 Roo.apply(Roo.bootstrap.NavGroup, {
3250 register : function(navgrp)
3252 this.groups[navgrp.navId] = navgrp;
3255 get: function(navId) {
3256 return this.groups[navId];
3271 * @class Roo.bootstrap.Navbar.Item
3272 * @extends Roo.bootstrap.Component
3273 * Bootstrap Navbar.Button class
3274 * @cfg {String} href link to
3275 * @cfg {String} html content of button
3276 * @cfg {String} badge text inside badge
3277 * @cfg {String} glyphicon name of glyphicon
3278 * @cfg {String} icon name of font awesome icon
3279 * @cfg {Boolean} active Is item active
3280 * @cfg {Boolean} preventDefault (true | false) default false
3281 * @cfg {String} tabId the tab that this item activates.
3284 * Create a new Navbar Button
3285 * @param {Object} config The config object
3287 Roo.bootstrap.Navbar.Item = function(config){
3288 Roo.bootstrap.Navbar.Item.superclass.constructor.call(this, config);
3293 * The raw click event for the entire grid.
3294 * @param {Roo.EventObject} e
3299 * Fires when the active item active state changes
3300 * @param {Roo.bootstrap.Navbar.Item} this
3301 * @param {boolean} state the new state
3309 Roo.extend(Roo.bootstrap.Navbar.Item, Roo.bootstrap.Component, {
3317 preventDefault : false,
3320 getAutoCreate : function(){
3322 var cfg = Roo.apply({}, Roo.bootstrap.Navbar.Item.superclass.getAutoCreate.call(this));
3324 if (this.parent().parent().sidebar === true) {
3337 cfg.cn[0].html = this.html;
3341 this.cls += ' active';
3345 cfg.cn[0].cls += ' dropdown-toggle';
3346 cfg.cn[0].html = (cfg.cn[0].html || this.html) + '<span class="glyphicon glyphicon-chevron-down"></span>';
3350 cfg.cn[0].tag = 'a',
3351 cfg.cn[0].href = this.href;
3354 if (this.glyphicon) {
3355 cfg.cn[0].html = '<i class="glyphicon glyphicon-'+this.glyphicon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
3359 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
3371 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3381 if (this.glyphicon) {
3382 if(cfg.html){cfg.html = ' ' + this.html};
3386 cls: 'glyphicon glyphicon-' + this.glyphicon
3391 cfg.cn[0].html = this.html || cfg.cn[0].html ;
3396 cfg.cn[0].html += " <span class='caret'></span>";
3397 //}else if (!this.href) {
3398 // cfg.cn[0].tag='p';
3399 // cfg.cn[0].cls='navbar-text';
3402 cfg.cn[0].href=this.href||'#';
3403 cfg.cn[0].html=this.html;
3406 if (this.badge !== '') {
3409 cfg.cn[0].html + ' ',
3420 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
3425 initEvents: function() {
3426 // Roo.log('init events?');
3427 // Roo.log(this.el.dom);
3428 this.el.select('a',true).on('click', this.onClick, this);
3429 // at this point parent should be available..
3430 this.parent().register(this);
3433 onClick : function(e)
3435 if(this.preventDefault){
3439 if(this.fireEvent('click', this, e) === false){
3443 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3444 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3445 this.parent().setActiveItem(this);
3453 isActive: function () {
3456 setActive : function(state, fire)
3458 this.active = state;
3460 this.el.removeClass('active');
3461 } else if (!this.el.hasClass('active')) {
3462 this.el.addClass('active');
3465 this.fireEvent('changed', this, state);
3470 // this should not be here...
3483 * @class Roo.bootstrap.NavItem
3484 * @extends Roo.bootstrap.Component
3485 * Bootstrap Navbar.NavItem class
3486 * @cfg {String} href link to
3487 * @cfg {String} html content of button
3488 * @cfg {String} badge text inside badge
3489 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3490 * @cfg {String} glyphicon name of glyphicon
3491 * @cfg {String} icon name of font awesome icon
3492 * @cfg {Boolean} active Is item active
3493 * @cfg {Boolean} preventDefault (true | false) default false
3494 * @cfg {String} tabId the tab that this item activates.
3497 * Create a new Navbar Item
3498 * @param {Object} config The config object
3500 Roo.bootstrap.NavItem = function(config){
3501 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3506 * The raw click event for the entire grid.
3507 * @param {Roo.EventObject} e
3512 * Fires when the active item active state changes
3513 * @param {Roo.bootstrap.NavItem} this
3514 * @param {boolean} state the new state
3522 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3530 preventDefault : false,
3533 getAutoCreate : function(){
3541 href : this.href || "#",
3542 html: this.html || ''
3548 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3551 // glyphicon and icon go before content..
3552 if (this.glyphicon || this.icon) {
3554 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html + '</span>'
3556 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span>' + cfg.cn[0].html;
3564 cfg.cn[0].html += " <span class='caret'></span>";
3568 if (this.badge !== '') {
3570 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3577 initEvents: function() {
3578 // Roo.log('init events?');
3579 // Roo.log(this.el.dom);
3580 this.el.select('a',true).on('click', this.onClick, this);
3581 // at this point parent should be available..
3582 this.parent().register(this);
3585 onClick : function(e)
3587 if(this.preventDefault){
3591 if(this.fireEvent('click', this, e) === false){
3595 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3596 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3597 this.parent().setActiveItem(this);
3605 isActive: function () {
3608 setActive : function(state, fire)
3610 this.active = state;
3612 this.el.removeClass('active');
3613 } else if (!this.el.hasClass('active')) {
3614 this.el.addClass('active');
3617 this.fireEvent('changed', this, state);
3622 // this should not be here...
3633 * <span> icon </span>
3634 * <span> text </span>
3635 * <span>badge </span>
3639 * @class Roo.bootstrap.NavSidebarItem
3640 * @extends Roo.bootstrap.Component
3641 * Bootstrap Navbar.NavSidebarItem class
3643 * Create a new Navbar Button
3644 * @param {Object} config The config object
3646 Roo.bootstrap.NavSidebarItem = function(config){
3647 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3652 * The raw click event for the entire grid.
3653 * @param {Roo.EventObject} e
3658 * Fires when the active item active state changes
3659 * @param {Roo.bootstrap.Navbar.Item} this
3660 * @param {boolean} state the new state
3668 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3671 getAutoCreate : function(){
3676 href : this.href || '#',
3688 html : this.html || ''
3693 cfg.cls += ' active';
3697 if (this.glyphicon || this.icon) {
3698 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3699 a.cn.push({ tag : 'i', cls : c }) ;
3704 if (this.badge !== '') {
3705 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3709 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3710 a.cls += 'dropdown-toggle treeview' ;
3734 * @class Roo.bootstrap.Row
3735 * @extends Roo.bootstrap.Component
3736 * Bootstrap Row class (contains columns...)
3740 * @param {Object} config The config object
3743 Roo.bootstrap.Row = function(config){
3744 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3747 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3749 getAutoCreate : function(){
3768 * @class Roo.bootstrap.Element
3769 * @extends Roo.bootstrap.Component
3770 * Bootstrap Element class
3771 * @cfg {String} html contents of the element
3772 * @cfg {String} tag tag of the element
3773 * @cfg {String} cls class of the element
3776 * Create a new Element
3777 * @param {Object} config The config object
3780 Roo.bootstrap.Element = function(config){
3781 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3784 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3791 getAutoCreate : function(){
3816 * @class Roo.bootstrap.Pagination
3817 * @extends Roo.bootstrap.Component
3818 * Bootstrap Pagination class
3819 * @cfg {String} size xs | sm | md | lg
3820 * @cfg {Boolean} inverse false | true
3823 * Create a new Pagination
3824 * @param {Object} config The config object
3827 Roo.bootstrap.Pagination = function(config){
3828 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3831 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3837 getAutoCreate : function(){
3843 cfg.cls += ' inverse';
3849 cfg.cls += " " + this.cls;
3867 * @class Roo.bootstrap.PaginationItem
3868 * @extends Roo.bootstrap.Component
3869 * Bootstrap PaginationItem class
3870 * @cfg {String} html text
3871 * @cfg {String} href the link
3872 * @cfg {Boolean} preventDefault (true | false) default true
3873 * @cfg {Boolean} active (true | false) default false
3877 * Create a new PaginationItem
3878 * @param {Object} config The config object
3882 Roo.bootstrap.PaginationItem = function(config){
3883 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3888 * The raw click event for the entire grid.
3889 * @param {Roo.EventObject} e
3895 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
3899 preventDefault: true,
3903 getAutoCreate : function(){
3909 href : this.href ? this.href : '#',
3910 html : this.html ? this.html : ''
3920 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
3926 initEvents: function() {
3928 this.el.on('click', this.onClick, this);
3931 onClick : function(e)
3933 Roo.log('PaginationItem on click ');
3934 if(this.preventDefault){
3938 this.fireEvent('click', this, e);
3954 * @class Roo.bootstrap.Slider
3955 * @extends Roo.bootstrap.Component
3956 * Bootstrap Slider class
3959 * Create a new Slider
3960 * @param {Object} config The config object
3963 Roo.bootstrap.Slider = function(config){
3964 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
3967 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
3969 getAutoCreate : function(){
3973 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
3977 cls: 'ui-slider-handle ui-state-default ui-corner-all'
3995 * @class Roo.bootstrap.Table
3996 * @extends Roo.bootstrap.Component
3997 * Bootstrap Table class
3998 * @cfg {String} cls table class
3999 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4000 * @cfg {String} bgcolor Specifies the background color for a table
4001 * @cfg {Number} border Specifies whether the table cells should have borders or not
4002 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4003 * @cfg {Number} cellspacing Specifies the space between cells
4004 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4005 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4006 * @cfg {String} sortable Specifies that the table should be sortable
4007 * @cfg {String} summary Specifies a summary of the content of a table
4008 * @cfg {Number} width Specifies the width of a table
4010 * @cfg {boolean} striped Should the rows be alternative striped
4011 * @cfg {boolean} bordered Add borders to the table
4012 * @cfg {boolean} hover Add hover highlighting
4013 * @cfg {boolean} condensed Format condensed
4014 * @cfg {boolean} responsive Format condensed
4020 * Create a new Table
4021 * @param {Object} config The config object
4024 Roo.bootstrap.Table = function(config){
4025 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4028 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4029 this.sm = this.selModel;
4030 this.sm.xmodule = this.xmodule || false;
4032 if (this.cm && typeof(this.cm.config) == 'undefined') {
4033 this.colModel = new Roo.bootstrap.Table.ColumnModel(this.cm);
4034 this.cm = this.colModel;
4035 this.cm.xmodule = this.xmodule || false;
4038 this.store= Roo.factory(this.store, Roo.data);
4039 this.ds = this.store;
4040 this.ds.xmodule = this.xmodule || false;
4045 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4067 getAutoCreate : function(){
4068 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4077 cfg.cls += ' table-striped';
4080 cfg.cls += ' table-hover';
4082 if (this.bordered) {
4083 cfg.cls += ' table-bordered';
4085 if (this.condensed) {
4086 cfg.cls += ' table-condensed';
4088 if (this.responsive) {
4089 cfg.cls += ' table-responsive';
4096 cfg.cls+= ' ' +this.cls;
4099 // this lot should be simplifed...
4102 cfg.align=this.align;
4105 cfg.bgcolor=this.bgcolor;
4108 cfg.border=this.border;
4110 if (this.cellpadding) {
4111 cfg.cellpadding=this.cellpadding;
4113 if (this.cellspacing) {
4114 cfg.cellspacing=this.cellspacing;
4117 cfg.frame=this.frame;
4120 cfg.rules=this.rules;
4122 if (this.sortable) {
4123 cfg.sortable=this.sortable;
4126 cfg.summary=this.summary;
4129 cfg.width=this.width;
4132 if(this.store || this.cm){
4133 cfg.cn.push(this.renderHeader());
4134 cfg.cn.push(this.renderBody());
4135 cfg.cn.push(this.renderFooter());
4137 cfg.cls+= ' TableGrid';
4143 // initTableGrid : function()
4152 // var cm = this.cm;
4154 // for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4157 // html: cm.getColumnHeader(i)
4161 // cfg.push(header);
4168 initEvents : function()
4170 if(!this.store || !this.cm){
4174 Roo.log('initEvents with ds!!!!');
4178 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4179 e.on('click', _this.sort, _this);
4181 // this.maskEl = Roo.DomHelper.append(this.el.select('.TableGrid', true).first(), {tag: "div", cls:"x-dlg-mask"}, true);
4182 // this.maskEl.enableDisplayMode("block");
4183 // this.maskEl.show();
4185 this.store.on('load', this.onLoad, this);
4186 this.store.on('beforeload', this.onBeforeLoad, this);
4194 sort : function(e,el)
4196 var col = Roo.get(el)
4198 if(!col.hasClass('sortable')){
4202 var sort = col.attr('sort');
4205 if(col.hasClass('glyphicon-arrow-up')){
4209 this.store.sortInfo = {field : sort, direction : dir};
4214 renderHeader : function()
4223 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4225 var config = cm.config[i];
4229 html: cm.getColumnHeader(i)
4232 if(typeof(config.dataIndex) != 'undefined'){
4233 c.sort = config.dataIndex;
4236 if(typeof(config.sortable) != 'undefined' && config.sortable){
4240 if(typeof(config.width) != 'undefined'){
4241 c.style = 'width:' + config.width + 'px';
4250 renderBody : function()
4260 renderFooter : function()
4272 Roo.log('ds onload');
4277 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4278 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
4280 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
4281 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
4284 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
4285 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
4289 var tbody = this.el.select('tbody', true).first();
4293 if(this.store.getCount() > 0){
4294 this.store.data.each(function(d){
4300 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4301 var renderer = cm.getRenderer(i);
4302 var config = cm.config[i];
4306 if(typeof(renderer) !== 'undefined'){
4307 value = renderer(d.data[cm.getDataIndex(i)], false, d);
4310 if(typeof(value) === 'object'){
4320 html: (typeof(value) === 'object') ? '' : value
4323 if(typeof(config.width) != 'undefined'){
4324 td.style = 'width:' + config.width + 'px';
4331 tbody.createChild(row);
4339 Roo.each(renders, function(r){
4340 _this.renderColumn(r);
4344 // if(this.loadMask){
4345 // this.maskEl.hide();
4349 onBeforeLoad : function()
4351 Roo.log('ds onBeforeLoad');
4355 // if(this.loadMask){
4356 // this.maskEl.show();
4362 this.el.select('tbody', true).first().dom.innerHTML = '';
4365 getSelectionModel : function(){
4367 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
4369 return this.selModel;
4372 renderColumn : function(r)
4375 r.cfg.render(Roo.get(r.id));
4378 Roo.each(r.cfg.cn, function(c){
4383 _this.renderColumn(child);
4400 * @class Roo.bootstrap.TableCell
4401 * @extends Roo.bootstrap.Component
4402 * Bootstrap TableCell class
4403 * @cfg {String} html cell contain text
4404 * @cfg {String} cls cell class
4405 * @cfg {String} tag cell tag (td|th) default td
4406 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
4407 * @cfg {String} align Aligns the content in a cell
4408 * @cfg {String} axis Categorizes cells
4409 * @cfg {String} bgcolor Specifies the background color of a cell
4410 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
4411 * @cfg {Number} colspan Specifies the number of columns a cell should span
4412 * @cfg {String} headers Specifies one or more header cells a cell is related to
4413 * @cfg {Number} height Sets the height of a cell
4414 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
4415 * @cfg {Number} rowspan Sets the number of rows a cell should span
4416 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
4417 * @cfg {String} valign Vertical aligns the content in a cell
4418 * @cfg {Number} width Specifies the width of a cell
4421 * Create a new TableCell
4422 * @param {Object} config The config object
4425 Roo.bootstrap.TableCell = function(config){
4426 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
4429 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
4449 getAutoCreate : function(){
4450 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
4470 cfg.align=this.align
4476 cfg.bgcolor=this.bgcolor
4479 cfg.charoff=this.charoff
4482 cfg.colspan=this.colspan
4485 cfg.headers=this.headers
4488 cfg.height=this.height
4491 cfg.nowrap=this.nowrap
4494 cfg.rowspan=this.rowspan
4497 cfg.scope=this.scope
4500 cfg.valign=this.valign
4503 cfg.width=this.width
4522 * @class Roo.bootstrap.TableRow
4523 * @extends Roo.bootstrap.Component
4524 * Bootstrap TableRow class
4525 * @cfg {String} cls row class
4526 * @cfg {String} align Aligns the content in a table row
4527 * @cfg {String} bgcolor Specifies a background color for a table row
4528 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
4529 * @cfg {String} valign Vertical aligns the content in a table row
4532 * Create a new TableRow
4533 * @param {Object} config The config object
4536 Roo.bootstrap.TableRow = function(config){
4537 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
4540 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
4548 getAutoCreate : function(){
4549 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
4559 cfg.align = this.align;
4562 cfg.bgcolor = this.bgcolor;
4565 cfg.charoff = this.charoff;
4568 cfg.valign = this.valign;
4586 * @class Roo.bootstrap.TableBody
4587 * @extends Roo.bootstrap.Component
4588 * Bootstrap TableBody class
4589 * @cfg {String} cls element class
4590 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
4591 * @cfg {String} align Aligns the content inside the element
4592 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
4593 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
4596 * Create a new TableBody
4597 * @param {Object} config The config object
4600 Roo.bootstrap.TableBody = function(config){
4601 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
4604 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
4612 getAutoCreate : function(){
4613 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
4627 cfg.align = this.align;
4630 cfg.charoff = this.charoff;
4633 cfg.valign = this.valign;
4640 // initEvents : function()
4647 // this.store = Roo.factory(this.store, Roo.data);
4648 // this.store.on('load', this.onLoad, this);
4650 // this.store.load();
4654 // onLoad: function ()
4656 // this.fireEvent('load', this);
4666 * Ext JS Library 1.1.1
4667 * Copyright(c) 2006-2007, Ext JS, LLC.
4669 * Originally Released Under LGPL - original licence link has changed is not relivant.
4672 * <script type="text/javascript">
4675 // as we use this in bootstrap.
4676 Roo.namespace('Roo.form');
4678 * @class Roo.form.Action
4679 * Internal Class used to handle form actions
4681 * @param {Roo.form.BasicForm} el The form element or its id
4682 * @param {Object} config Configuration options
4687 // define the action interface
4688 Roo.form.Action = function(form, options){
4690 this.options = options || {};
4693 * Client Validation Failed
4696 Roo.form.Action.CLIENT_INVALID = 'client';
4698 * Server Validation Failed
4701 Roo.form.Action.SERVER_INVALID = 'server';
4703 * Connect to Server Failed
4706 Roo.form.Action.CONNECT_FAILURE = 'connect';
4708 * Reading Data from Server Failed
4711 Roo.form.Action.LOAD_FAILURE = 'load';
4713 Roo.form.Action.prototype = {
4715 failureType : undefined,
4716 response : undefined,
4720 run : function(options){
4725 success : function(response){
4730 handleResponse : function(response){
4734 // default connection failure
4735 failure : function(response){
4737 this.response = response;
4738 this.failureType = Roo.form.Action.CONNECT_FAILURE;
4739 this.form.afterAction(this, false);
4742 processResponse : function(response){
4743 this.response = response;
4744 if(!response.responseText){
4747 this.result = this.handleResponse(response);
4751 // utility functions used internally
4752 getUrl : function(appendParams){
4753 var url = this.options.url || this.form.url || this.form.el.dom.action;
4755 var p = this.getParams();
4757 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
4763 getMethod : function(){
4764 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
4767 getParams : function(){
4768 var bp = this.form.baseParams;
4769 var p = this.options.params;
4771 if(typeof p == "object"){
4772 p = Roo.urlEncode(Roo.applyIf(p, bp));
4773 }else if(typeof p == 'string' && bp){
4774 p += '&' + Roo.urlEncode(bp);
4777 p = Roo.urlEncode(bp);
4782 createCallback : function(){
4784 success: this.success,
4785 failure: this.failure,
4787 timeout: (this.form.timeout*1000),
4788 upload: this.form.fileUpload ? this.success : undefined
4793 Roo.form.Action.Submit = function(form, options){
4794 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
4797 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
4800 haveProgress : false,
4801 uploadComplete : false,
4803 // uploadProgress indicator.
4804 uploadProgress : function()
4806 if (!this.form.progressUrl) {
4810 if (!this.haveProgress) {
4811 Roo.MessageBox.progress("Uploading", "Uploading");
4813 if (this.uploadComplete) {
4814 Roo.MessageBox.hide();
4818 this.haveProgress = true;
4820 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
4822 var c = new Roo.data.Connection();
4824 url : this.form.progressUrl,
4829 success : function(req){
4830 //console.log(data);
4834 rdata = Roo.decode(req.responseText)
4836 Roo.log("Invalid data from server..");
4840 if (!rdata || !rdata.success) {
4842 Roo.MessageBox.alert(Roo.encode(rdata));
4845 var data = rdata.data;
4847 if (this.uploadComplete) {
4848 Roo.MessageBox.hide();
4853 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
4854 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
4857 this.uploadProgress.defer(2000,this);
4860 failure: function(data) {
4861 Roo.log('progress url failed ');
4872 // run get Values on the form, so it syncs any secondary forms.
4873 this.form.getValues();
4875 var o = this.options;
4876 var method = this.getMethod();
4877 var isPost = method == 'POST';
4878 if(o.clientValidation === false || this.form.isValid()){
4880 if (this.form.progressUrl) {
4881 this.form.findField('UPLOAD_IDENTIFIER').setValue(
4882 (new Date() * 1) + '' + Math.random());
4887 Roo.Ajax.request(Roo.apply(this.createCallback(), {
4888 form:this.form.el.dom,
4889 url:this.getUrl(!isPost),
4891 params:isPost ? this.getParams() : null,
4892 isUpload: this.form.fileUpload
4895 this.uploadProgress();
4897 }else if (o.clientValidation !== false){ // client validation failed
4898 this.failureType = Roo.form.Action.CLIENT_INVALID;
4899 this.form.afterAction(this, false);
4903 success : function(response)
4905 this.uploadComplete= true;
4906 if (this.haveProgress) {
4907 Roo.MessageBox.hide();
4911 var result = this.processResponse(response);
4912 if(result === true || result.success){
4913 this.form.afterAction(this, true);
4917 this.form.markInvalid(result.errors);
4918 this.failureType = Roo.form.Action.SERVER_INVALID;
4920 this.form.afterAction(this, false);
4922 failure : function(response)
4924 this.uploadComplete= true;
4925 if (this.haveProgress) {
4926 Roo.MessageBox.hide();
4929 this.response = response;
4930 this.failureType = Roo.form.Action.CONNECT_FAILURE;
4931 this.form.afterAction(this, false);
4934 handleResponse : function(response){
4935 if(this.form.errorReader){
4936 var rs = this.form.errorReader.read(response);
4939 for(var i = 0, len = rs.records.length; i < len; i++) {
4940 var r = rs.records[i];
4944 if(errors.length < 1){
4948 success : rs.success,
4954 ret = Roo.decode(response.responseText);
4958 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
4968 Roo.form.Action.Load = function(form, options){
4969 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
4970 this.reader = this.form.reader;
4973 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
4978 Roo.Ajax.request(Roo.apply(
4979 this.createCallback(), {
4980 method:this.getMethod(),
4981 url:this.getUrl(false),
4982 params:this.getParams()
4986 success : function(response){
4988 var result = this.processResponse(response);
4989 if(result === true || !result.success || !result.data){
4990 this.failureType = Roo.form.Action.LOAD_FAILURE;
4991 this.form.afterAction(this, false);
4994 this.form.clearInvalid();
4995 this.form.setValues(result.data);
4996 this.form.afterAction(this, true);
4999 handleResponse : function(response){
5000 if(this.form.reader){
5001 var rs = this.form.reader.read(response);
5002 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
5004 success : rs.success,
5008 return Roo.decode(response.responseText);
5012 Roo.form.Action.ACTION_TYPES = {
5013 'load' : Roo.form.Action.Load,
5014 'submit' : Roo.form.Action.Submit
5023 * @class Roo.bootstrap.Form
5024 * @extends Roo.bootstrap.Component
5025 * Bootstrap Form class
5026 * @cfg {String} method GET | POST (default POST)
5027 * @cfg {String} labelAlign top | left (default top)
5028 * @cfg {String} align left | right - for navbars
5033 * @param {Object} config The config object
5037 Roo.bootstrap.Form = function(config){
5038 Roo.bootstrap.Form.superclass.constructor.call(this, config);
5041 * @event clientvalidation
5042 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
5043 * @param {Form} this
5044 * @param {Boolean} valid true if the form has passed client-side validation
5046 clientvalidation: true,
5048 * @event beforeaction
5049 * Fires before any action is performed. Return false to cancel the action.
5050 * @param {Form} this
5051 * @param {Action} action The action to be performed
5055 * @event actionfailed
5056 * Fires when an action fails.
5057 * @param {Form} this
5058 * @param {Action} action The action that failed
5060 actionfailed : true,
5062 * @event actioncomplete
5063 * Fires when an action is completed.
5064 * @param {Form} this
5065 * @param {Action} action The action that completed
5067 actioncomplete : true
5072 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
5075 * @cfg {String} method
5076 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
5081 * The URL to use for form actions if one isn't supplied in the action options.
5084 * @cfg {Boolean} fileUpload
5085 * Set to true if this form is a file upload.
5089 * @cfg {Object} baseParams
5090 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
5094 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
5098 * @cfg {Sting} align (left|right) for navbar forms
5103 activeAction : null,
5106 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5107 * element by passing it or its id or mask the form itself by passing in true.
5110 waitMsgTarget : false,
5115 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5116 * element by passing it or its id or mask the form itself by passing in true.
5120 getAutoCreate : function(){
5124 method : this.method || 'POST',
5125 id : this.id || Roo.id(),
5128 if (this.parent().xtype.match(/^Nav/)) {
5129 cfg.cls = 'navbar-form navbar-' + this.align;
5133 if (this.labelAlign == 'left' ) {
5134 cfg.cls += ' form-horizontal';
5140 initEvents : function()
5142 this.el.on('submit', this.onSubmit, this);
5147 onSubmit : function(e){
5152 * Returns true if client-side validation on the form is successful.
5155 isValid : function(){
5156 var items = this.getItems();
5158 items.each(function(f){
5167 * Returns true if any fields in this form have changed since their original load.
5170 isDirty : function(){
5172 var items = this.getItems();
5173 items.each(function(f){
5183 * Performs a predefined action (submit or load) or custom actions you define on this form.
5184 * @param {String} actionName The name of the action type
5185 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
5186 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
5187 * accept other config options):
5189 Property Type Description
5190 ---------------- --------------- ----------------------------------------------------------------------------------
5191 url String The url for the action (defaults to the form's url)
5192 method String The form method to use (defaults to the form's method, or POST if not defined)
5193 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
5194 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
5195 validate the form on the client (defaults to false)
5197 * @return {BasicForm} this
5199 doAction : function(action, options){
5200 if(typeof action == 'string'){
5201 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
5203 if(this.fireEvent('beforeaction', this, action) !== false){
5204 this.beforeAction(action);
5205 action.run.defer(100, action);
5211 beforeAction : function(action){
5212 var o = action.options;
5214 // not really supported yet.. ??
5216 //if(this.waitMsgTarget === true){
5217 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
5218 //}else if(this.waitMsgTarget){
5219 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
5220 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
5222 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
5228 afterAction : function(action, success){
5229 this.activeAction = null;
5230 var o = action.options;
5232 //if(this.waitMsgTarget === true){
5234 //}else if(this.waitMsgTarget){
5235 // this.waitMsgTarget.unmask();
5237 // Roo.MessageBox.updateProgress(1);
5238 // Roo.MessageBox.hide();
5245 Roo.callback(o.success, o.scope, [this, action]);
5246 this.fireEvent('actioncomplete', this, action);
5250 // failure condition..
5251 // we have a scenario where updates need confirming.
5252 // eg. if a locking scenario exists..
5253 // we look for { errors : { needs_confirm : true }} in the response.
5255 (typeof(action.result) != 'undefined') &&
5256 (typeof(action.result.errors) != 'undefined') &&
5257 (typeof(action.result.errors.needs_confirm) != 'undefined')
5260 Roo.log("not supported yet");
5263 Roo.MessageBox.confirm(
5264 "Change requires confirmation",
5265 action.result.errorMsg,
5270 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
5280 Roo.callback(o.failure, o.scope, [this, action]);
5281 // show an error message if no failed handler is set..
5282 if (!this.hasListener('actionfailed')) {
5283 Roo.log("need to add dialog support");
5285 Roo.MessageBox.alert("Error",
5286 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
5287 action.result.errorMsg :
5288 "Saving Failed, please check your entries or try again"
5293 this.fireEvent('actionfailed', this, action);
5298 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
5299 * @param {String} id The value to search for
5302 findField : function(id){
5303 var items = this.getItems();
5304 var field = items.get(id);
5306 items.each(function(f){
5307 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
5314 return field || null;
5317 * Mark fields in this form invalid in bulk.
5318 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
5319 * @return {BasicForm} this
5321 markInvalid : function(errors){
5322 if(errors instanceof Array){
5323 for(var i = 0, len = errors.length; i < len; i++){
5324 var fieldError = errors[i];
5325 var f = this.findField(fieldError.id);
5327 f.markInvalid(fieldError.msg);
5333 if(typeof errors[id] != 'function' && (field = this.findField(id))){
5334 field.markInvalid(errors[id]);
5338 //Roo.each(this.childForms || [], function (f) {
5339 // f.markInvalid(errors);
5346 * Set values for fields in this form in bulk.
5347 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
5348 * @return {BasicForm} this
5350 setValues : function(values){
5351 if(values instanceof Array){ // array of objects
5352 for(var i = 0, len = values.length; i < len; i++){
5354 var f = this.findField(v.id);
5356 f.setValue(v.value);
5357 if(this.trackResetOnLoad){
5358 f.originalValue = f.getValue();
5362 }else{ // object hash
5365 if(typeof values[id] != 'function' && (field = this.findField(id))){
5367 if (field.setFromData &&
5369 field.displayField &&
5370 // combos' with local stores can
5371 // be queried via setValue()
5372 // to set their value..
5373 (field.store && !field.store.isLocal)
5377 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
5378 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
5379 field.setFromData(sd);
5382 field.setValue(values[id]);
5386 if(this.trackResetOnLoad){
5387 field.originalValue = field.getValue();
5393 //Roo.each(this.childForms || [], function (f) {
5394 // f.setValues(values);
5401 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
5402 * they are returned as an array.
5403 * @param {Boolean} asString
5406 getValues : function(asString){
5407 //if (this.childForms) {
5408 // copy values from the child forms
5409 // Roo.each(this.childForms, function (f) {
5410 // this.setValues(f.getValues());
5416 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
5417 if(asString === true){
5420 return Roo.urlDecode(fs);
5424 * Returns the fields in this form as an object with key/value pairs.
5425 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
5428 getFieldValues : function(with_hidden)
5430 var items = this.getItems();
5432 items.each(function(f){
5436 var v = f.getValue();
5437 if (f.inputType =='radio') {
5438 if (typeof(ret[f.getName()]) == 'undefined') {
5439 ret[f.getName()] = ''; // empty..
5442 if (!f.el.dom.checked) {
5450 // not sure if this supported any more..
5451 if ((typeof(v) == 'object') && f.getRawValue) {
5452 v = f.getRawValue() ; // dates..
5454 // combo boxes where name != hiddenName...
5455 if (f.name != f.getName()) {
5456 ret[f.name] = f.getRawValue();
5458 ret[f.getName()] = v;
5465 * Clears all invalid messages in this form.
5466 * @return {BasicForm} this
5468 clearInvalid : function(){
5469 var items = this.getItems();
5471 items.each(function(f){
5482 * @return {BasicForm} this
5485 var items = this.getItems();
5486 items.each(function(f){
5490 Roo.each(this.childForms || [], function (f) {
5497 getItems : function()
5499 var r=new Roo.util.MixedCollection(false, function(o){
5500 return o.id || (o.id = Roo.id());
5502 var iter = function(el) {
5509 Roo.each(el.items,function(e) {
5528 * Ext JS Library 1.1.1
5529 * Copyright(c) 2006-2007, Ext JS, LLC.
5531 * Originally Released Under LGPL - original licence link has changed is not relivant.
5534 * <script type="text/javascript">
5537 * @class Roo.form.VTypes
5538 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
5541 Roo.form.VTypes = function(){
5542 // closure these in so they are only created once.
5543 var alpha = /^[a-zA-Z_]+$/;
5544 var alphanum = /^[a-zA-Z0-9_]+$/;
5545 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
5546 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
5548 // All these messages and functions are configurable
5551 * The function used to validate email addresses
5552 * @param {String} value The email address
5554 'email' : function(v){
5555 return email.test(v);
5558 * The error text to display when the email validation function returns false
5561 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
5563 * The keystroke filter mask to be applied on email input
5566 'emailMask' : /[a-z0-9_\.\-@]/i,
5569 * The function used to validate URLs
5570 * @param {String} value The URL
5572 'url' : function(v){
5576 * The error text to display when the url validation function returns false
5579 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
5582 * The function used to validate alpha values
5583 * @param {String} value The value
5585 'alpha' : function(v){
5586 return alpha.test(v);
5589 * The error text to display when the alpha validation function returns false
5592 'alphaText' : 'This field should only contain letters and _',
5594 * The keystroke filter mask to be applied on alpha input
5597 'alphaMask' : /[a-z_]/i,
5600 * The function used to validate alphanumeric values
5601 * @param {String} value The value
5603 'alphanum' : function(v){
5604 return alphanum.test(v);
5607 * The error text to display when the alphanumeric validation function returns false
5610 'alphanumText' : 'This field should only contain letters, numbers and _',
5612 * The keystroke filter mask to be applied on alphanumeric input
5615 'alphanumMask' : /[a-z0-9_]/i
5625 * @class Roo.bootstrap.Input
5626 * @extends Roo.bootstrap.Component
5627 * Bootstrap Input class
5628 * @cfg {Boolean} disabled is it disabled
5629 * @cfg {String} fieldLabel - the label associated
5630 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
5631 * @cfg {String} name name of the input
5632 * @cfg {string} fieldLabel - the label associated
5633 * @cfg {string} inputType - input / file submit ...
5634 * @cfg {string} placeholder - placeholder to put in text.
5635 * @cfg {string} before - input group add on before
5636 * @cfg {string} after - input group add on after
5637 * @cfg {string} size - (lg|sm) or leave empty..
5638 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
5639 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
5640 * @cfg {Number} md colspan out of 12 for computer-sized screens
5641 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
5642 * @cfg {string} value default value of the input
5643 * @cfg {Number} labelWidth set the width of label (0-12)
5644 * @cfg {String} labelAlign (top|left)
5645 * @cfg {Boolean} readOnly Specifies that the field should be read-only
5649 * Create a new Input
5650 * @param {Object} config The config object
5653 Roo.bootstrap.Input = function(config){
5654 Roo.bootstrap.Input.superclass.constructor.call(this, config);
5659 * Fires when this field receives input focus.
5660 * @param {Roo.form.Field} this
5665 * Fires when this field loses input focus.
5666 * @param {Roo.form.Field} this
5671 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
5672 * {@link Roo.EventObject#getKey} to determine which key was pressed.
5673 * @param {Roo.form.Field} this
5674 * @param {Roo.EventObject} e The event object
5679 * Fires just before the field blurs if the field value has changed.
5680 * @param {Roo.form.Field} this
5681 * @param {Mixed} newValue The new value
5682 * @param {Mixed} oldValue The original value
5687 * Fires after the field has been marked as invalid.
5688 * @param {Roo.form.Field} this
5689 * @param {String} msg The validation message
5694 * Fires after the field has been validated with no errors.
5695 * @param {Roo.form.Field} this
5700 * Fires after the key up
5701 * @param {Roo.form.Field} this
5702 * @param {Roo.EventObject} e The event Object
5708 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
5710 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
5711 automatic validation (defaults to "keyup").
5713 validationEvent : "keyup",
5715 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
5717 validateOnBlur : true,
5719 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
5721 validationDelay : 250,
5723 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
5725 focusClass : "x-form-focus", // not needed???
5729 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
5731 invalidClass : "has-error",
5734 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
5736 selectOnFocus : false,
5739 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
5743 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
5748 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
5750 disableKeyFilter : false,
5753 * @cfg {Boolean} disabled True to disable the field (defaults to false).
5757 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
5761 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
5763 blankText : "This field is required",
5766 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
5770 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
5772 maxLength : Number.MAX_VALUE,
5774 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
5776 minLengthText : "The minimum length for this field is {0}",
5778 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
5780 maxLengthText : "The maximum length for this field is {0}",
5784 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
5785 * If available, this function will be called only after the basic validators all return true, and will be passed the
5786 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
5790 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
5791 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
5792 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
5796 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
5819 parentLabelAlign : function()
5822 while (parent.parent()) {
5823 parent = parent.parent();
5824 if (typeof(parent.labelAlign) !='undefined') {
5825 return parent.labelAlign;
5832 getAutoCreate : function(){
5834 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
5840 if(this.inputType != 'hidden'){
5841 cfg.cls = 'form-group' //input-group
5847 type : this.inputType,
5849 cls : 'form-control',
5850 placeholder : this.placeholder || ''
5854 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
5855 input.maxLength = this.maxLength;
5858 if (this.disabled) {
5859 input.disabled=true;
5862 if (this.readOnly) {
5863 input.readonly=true;
5867 input.name = this.name;
5870 input.cls += ' input-' + this.size;
5873 ['xs','sm','md','lg'].map(function(size){
5874 if (settings[size]) {
5875 cfg.cls += ' col-' + size + '-' + settings[size];
5879 var inputblock = input;
5881 if (this.before || this.after) {
5884 cls : 'input-group',
5888 inputblock.cn.push({
5890 cls : 'input-group-addon',
5894 inputblock.cn.push(input);
5896 inputblock.cn.push({
5898 cls : 'input-group-addon',
5905 if (align ==='left' && this.fieldLabel.length) {
5906 Roo.log("left and has label");
5912 cls : 'control-label col-sm-' + this.labelWidth,
5913 html : this.fieldLabel
5917 cls : "col-sm-" + (12 - this.labelWidth),
5924 } else if ( this.fieldLabel.length) {
5930 //cls : 'input-group-addon',
5931 html : this.fieldLabel
5941 Roo.log(" no label && no align");
5950 Roo.log('input-parentType: ' + this.parentType);
5952 if (this.parentType === 'Navbar' && this.parent().bar) {
5953 cfg.cls += ' navbar-form';
5961 * return the real input element.
5963 inputEl: function ()
5965 return this.el.select('input.form-control',true).first();
5967 setDisabled : function(v)
5969 var i = this.inputEl().dom;
5971 i.removeAttribute('disabled');
5975 i.setAttribute('disabled','true');
5977 initEvents : function()
5980 this.inputEl().on("keydown" , this.fireKey, this);
5981 this.inputEl().on("focus", this.onFocus, this);
5982 this.inputEl().on("blur", this.onBlur, this);
5984 this.inputEl().relayEvent('keyup', this);
5986 // reference to original value for reset
5987 this.originalValue = this.getValue();
5988 //Roo.form.TextField.superclass.initEvents.call(this);
5989 if(this.validationEvent == 'keyup'){
5990 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
5991 this.inputEl().on('keyup', this.filterValidation, this);
5993 else if(this.validationEvent !== false){
5994 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
5997 if(this.selectOnFocus){
5998 this.on("focus", this.preFocus, this);
6001 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
6002 this.inputEl().on("keypress", this.filterKeys, this);
6005 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
6006 this.el.on("click", this.autoSize, this);
6009 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
6010 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
6014 filterValidation : function(e){
6015 if(!e.isNavKeyPress()){
6016 this.validationTask.delay(this.validationDelay);
6020 * Validates the field value
6021 * @return {Boolean} True if the value is valid, else false
6023 validate : function(){
6024 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
6025 if(this.disabled || this.validateValue(this.getRawValue())){
6026 this.clearInvalid();
6034 * Validates a value according to the field's validation rules and marks the field as invalid
6035 * if the validation fails
6036 * @param {Mixed} value The value to validate
6037 * @return {Boolean} True if the value is valid, else false
6039 validateValue : function(value){
6040 if(value.length < 1) { // if it's blank
6041 if(this.allowBlank){
6042 this.clearInvalid();
6045 this.markInvalid(this.blankText);
6049 if(value.length < this.minLength){
6050 this.markInvalid(String.format(this.minLengthText, this.minLength));
6053 if(value.length > this.maxLength){
6054 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
6058 var vt = Roo.form.VTypes;
6059 if(!vt[this.vtype](value, this)){
6060 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
6064 if(typeof this.validator == "function"){
6065 var msg = this.validator(value);
6067 this.markInvalid(msg);
6071 if(this.regex && !this.regex.test(value)){
6072 this.markInvalid(this.regexText);
6081 fireKey : function(e){
6082 //Roo.log('field ' + e.getKey());
6083 if(e.isNavKeyPress()){
6084 this.fireEvent("specialkey", this, e);
6087 focus : function (selectText){
6089 this.inputEl().focus();
6090 if(selectText === true){
6091 this.inputEl().dom.select();
6097 onFocus : function(){
6098 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6099 // this.el.addClass(this.focusClass);
6102 this.hasFocus = true;
6103 this.startValue = this.getValue();
6104 this.fireEvent("focus", this);
6108 beforeBlur : Roo.emptyFn,
6112 onBlur : function(){
6114 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6115 //this.el.removeClass(this.focusClass);
6117 this.hasFocus = false;
6118 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
6121 var v = this.getValue();
6122 if(String(v) !== String(this.startValue)){
6123 this.fireEvent('change', this, v, this.startValue);
6125 this.fireEvent("blur", this);
6129 * Resets the current field value to the originally loaded value and clears any validation messages
6132 this.setValue(this.originalValue);
6133 this.clearInvalid();
6136 * Returns the name of the field
6137 * @return {Mixed} name The name field
6139 getName: function(){
6143 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
6144 * @return {Mixed} value The field value
6146 getValue : function(){
6147 return this.inputEl().getValue();
6150 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
6151 * @return {Mixed} value The field value
6153 getRawValue : function(){
6154 var v = this.inputEl().getValue();
6160 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
6161 * @param {Mixed} value The value to set
6163 setRawValue : function(v){
6164 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6167 selectText : function(start, end){
6168 var v = this.getRawValue();
6170 start = start === undefined ? 0 : start;
6171 end = end === undefined ? v.length : end;
6172 var d = this.inputEl().dom;
6173 if(d.setSelectionRange){
6174 d.setSelectionRange(start, end);
6175 }else if(d.createTextRange){
6176 var range = d.createTextRange();
6177 range.moveStart("character", start);
6178 range.moveEnd("character", v.length-end);
6185 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
6186 * @param {Mixed} value The value to set
6188 setValue : function(v){
6191 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6197 processValue : function(value){
6198 if(this.stripCharsRe){
6199 var newValue = value.replace(this.stripCharsRe, '');
6200 if(newValue !== value){
6201 this.setRawValue(newValue);
6208 preFocus : function(){
6210 if(this.selectOnFocus){
6211 this.inputEl().dom.select();
6214 filterKeys : function(e){
6216 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
6219 var c = e.getCharCode(), cc = String.fromCharCode(c);
6220 if(Roo.isIE && (e.isSpecialKey() || !cc)){
6223 if(!this.maskRe.test(cc)){
6228 * Clear any invalid styles/messages for this field
6230 clearInvalid : function(){
6232 if(!this.el || this.preventMark){ // not rendered
6235 this.el.removeClass(this.invalidClass);
6237 switch(this.msgTarget){
6239 this.el.dom.qtip = '';
6242 this.el.dom.title = '';
6246 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
6251 this.errorIcon.dom.qtip = '';
6252 this.errorIcon.hide();
6253 this.un('resize', this.alignErrorIcon, this);
6257 var t = Roo.getDom(this.msgTarget);
6259 t.style.display = 'none';
6263 this.fireEvent('valid', this);
6266 * Mark this field as invalid
6267 * @param {String} msg The validation message
6269 markInvalid : function(msg){
6270 if(!this.el || this.preventMark){ // not rendered
6273 this.el.addClass(this.invalidClass);
6275 msg = msg || this.invalidText;
6276 switch(this.msgTarget){
6278 this.el.dom.qtip = msg;
6279 this.el.dom.qclass = 'x-form-invalid-tip';
6280 if(Roo.QuickTips){ // fix for floating editors interacting with DND
6281 Roo.QuickTips.enable();
6285 this.el.dom.title = msg;
6289 var elp = this.el.findParent('.x-form-element', 5, true);
6290 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
6291 this.errorEl.setWidth(elp.getWidth(true)-20);
6293 this.errorEl.update(msg);
6294 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
6297 if(!this.errorIcon){
6298 var elp = this.el.findParent('.x-form-element', 5, true);
6299 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
6301 this.alignErrorIcon();
6302 this.errorIcon.dom.qtip = msg;
6303 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
6304 this.errorIcon.show();
6305 this.on('resize', this.alignErrorIcon, this);
6308 var t = Roo.getDom(this.msgTarget);
6310 t.style.display = this.msgDisplay;
6314 this.fireEvent('invalid', this, msg);
6317 SafariOnKeyDown : function(event)
6319 // this is a workaround for a password hang bug on chrome/ webkit.
6321 var isSelectAll = false;
6323 if(this.inputEl().dom.selectionEnd > 0){
6324 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
6326 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
6327 event.preventDefault();
6332 if(isSelectAll){ // backspace and delete key
6334 event.preventDefault();
6335 // this is very hacky as keydown always get's upper case.
6337 var cc = String.fromCharCode(event.getCharCode());
6338 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
6342 adjustWidth : function(tag, w){
6343 tag = tag.toLowerCase();
6344 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
6345 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
6349 if(tag == 'textarea'){
6352 }else if(Roo.isOpera){
6356 if(tag == 'textarea'){
6375 * @class Roo.bootstrap.TextArea
6376 * @extends Roo.bootstrap.Input
6377 * Bootstrap TextArea class
6378 * @cfg {Number} cols Specifies the visible width of a text area
6379 * @cfg {Number} rows Specifies the visible number of lines in a text area
6380 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
6381 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
6382 * @cfg {string} html text
6385 * Create a new TextArea
6386 * @param {Object} config The config object
6389 Roo.bootstrap.TextArea = function(config){
6390 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
6394 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
6404 getAutoCreate : function(){
6406 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6417 value : this.value || '',
6418 html: this.html || '',
6419 cls : 'form-control',
6420 placeholder : this.placeholder || ''
6424 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6425 input.maxLength = this.maxLength;
6429 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
6433 input.cols = this.cols;
6436 if (this.readOnly) {
6437 input.readonly = true;
6441 input.name = this.name;
6445 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
6449 ['xs','sm','md','lg'].map(function(size){
6450 if (settings[size]) {
6451 cfg.cls += ' col-' + size + '-' + settings[size];
6455 var inputblock = input;
6457 if (this.before || this.after) {
6460 cls : 'input-group',
6464 inputblock.cn.push({
6466 cls : 'input-group-addon',
6470 inputblock.cn.push(input);
6472 inputblock.cn.push({
6474 cls : 'input-group-addon',
6481 if (align ==='left' && this.fieldLabel.length) {
6482 Roo.log("left and has label");
6488 cls : 'control-label col-sm-' + this.labelWidth,
6489 html : this.fieldLabel
6493 cls : "col-sm-" + (12 - this.labelWidth),
6500 } else if ( this.fieldLabel.length) {
6506 //cls : 'input-group-addon',
6507 html : this.fieldLabel
6517 Roo.log(" no label && no align");
6527 if (this.disabled) {
6528 input.disabled=true;
6535 * return the real textarea element.
6537 inputEl: function ()
6539 return this.el.select('textarea.form-control',true).first();
6547 * trigger field - base class for combo..
6552 * @class Roo.bootstrap.TriggerField
6553 * @extends Roo.bootstrap.Input
6554 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
6555 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
6556 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
6557 * for which you can provide a custom implementation. For example:
6559 var trigger = new Roo.bootstrap.TriggerField();
6560 trigger.onTriggerClick = myTriggerFn;
6561 trigger.applyTo('my-field');
6564 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
6565 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
6566 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
6567 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
6569 * Create a new TriggerField.
6570 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
6571 * to the base TextField)
6573 Roo.bootstrap.TriggerField = function(config){
6574 this.mimicing = false;
6575 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
6578 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
6580 * @cfg {String} triggerClass A CSS class to apply to the trigger
6583 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
6587 /** @cfg {Boolean} grow @hide */
6588 /** @cfg {Number} growMin @hide */
6589 /** @cfg {Number} growMax @hide */
6595 autoSize: Roo.emptyFn,
6602 actionMode : 'wrap',
6606 getAutoCreate : function(){
6608 var parent = this.parent();
6610 var align = this.parentLabelAlign();
6615 cls: 'form-group' //input-group
6622 type : this.inputType,
6623 cls : 'form-control',
6624 autocomplete: 'off',
6625 placeholder : this.placeholder || ''
6629 input.name = this.name;
6632 input.cls += ' input-' + this.size;
6635 if (this.disabled) {
6636 input.disabled=true;
6639 var inputblock = input;
6641 if (this.before || this.after) {
6644 cls : 'input-group',
6648 inputblock.cn.push({
6650 cls : 'input-group-addon',
6654 inputblock.cn.push(input);
6656 inputblock.cn.push({
6658 cls : 'input-group-addon',
6671 cls: 'form-hidden-field'
6679 Roo.log('multiple');
6687 cls: 'form-hidden-field'
6691 cls: 'select2-choices',
6695 cls: 'select2-search-field',
6708 cls: 'select2-container input-group',
6713 cls: 'typeahead typeahead-long dropdown-menu',
6714 style: 'display:none'
6722 cls : 'input-group-addon btn dropdown-toggle',
6730 cls: 'combobox-clear',
6744 combobox.cls += ' select2-container-multi';
6747 if (align ==='left' && this.fieldLabel.length) {
6749 Roo.log("left and has label");
6755 cls : 'control-label col-sm-' + this.labelWidth,
6756 html : this.fieldLabel
6760 cls : "col-sm-" + (12 - this.labelWidth),
6767 } else if ( this.fieldLabel.length) {
6773 //cls : 'input-group-addon',
6774 html : this.fieldLabel
6784 Roo.log(" no label && no align");
6791 ['xs','sm','md','lg'].map(function(size){
6792 if (settings[size]) {
6793 cfg.cls += ' col-' + size + '-' + settings[size];
6804 onResize : function(w, h){
6805 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
6806 // if(typeof w == 'number'){
6807 // var x = w - this.trigger.getWidth();
6808 // this.inputEl().setWidth(this.adjustWidth('input', x));
6809 // this.trigger.setStyle('left', x+'px');
6814 adjustSize : Roo.BoxComponent.prototype.adjustSize,
6817 getResizeEl : function(){
6818 return this.inputEl();
6822 getPositionEl : function(){
6823 return this.inputEl();
6827 alignErrorIcon : function(){
6828 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
6832 initEvents : function(){
6834 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
6835 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
6837 this.trigger = this.el.select('span.dropdown-toggle',true).first();
6838 if(this.hideTrigger){
6839 this.trigger.setDisplayed(false);
6841 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
6845 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
6848 //this.trigger.addClassOnOver('x-form-trigger-over');
6849 //this.trigger.addClassOnClick('x-form-trigger-click');
6852 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
6857 initTrigger : function(){
6862 onDestroy : function(){
6864 this.trigger.removeAllListeners();
6865 // this.trigger.remove();
6868 // this.wrap.remove();
6870 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
6874 onFocus : function(){
6875 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
6878 this.wrap.addClass('x-trigger-wrap-focus');
6879 this.mimicing = true;
6880 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
6881 if(this.monitorTab){
6882 this.el.on("keydown", this.checkTab, this);
6889 checkTab : function(e){
6890 if(e.getKey() == e.TAB){
6896 onBlur : function(){
6901 mimicBlur : function(e, t){
6903 if(!this.wrap.contains(t) && this.validateBlur()){
6910 triggerBlur : function(){
6911 this.mimicing = false;
6912 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
6913 if(this.monitorTab){
6914 this.el.un("keydown", this.checkTab, this);
6916 //this.wrap.removeClass('x-trigger-wrap-focus');
6917 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
6921 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
6922 validateBlur : function(e, t){
6927 onDisable : function(){
6928 Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
6930 // this.wrap.addClass('x-item-disabled');
6935 onEnable : function(){
6936 Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
6938 // this.el.removeClass('x-item-disabled');
6943 onShow : function(){
6944 var ae = this.getActionEl();
6947 ae.dom.style.display = '';
6948 ae.dom.style.visibility = 'visible';
6954 onHide : function(){
6955 var ae = this.getActionEl();
6956 ae.dom.style.display = 'none';
6960 * The function that should handle the trigger's click event. This method does nothing by default until overridden
6961 * by an implementing function.
6963 * @param {EventObject} e
6965 onTriggerClick : Roo.emptyFn
6969 * Ext JS Library 1.1.1
6970 * Copyright(c) 2006-2007, Ext JS, LLC.
6972 * Originally Released Under LGPL - original licence link has changed is not relivant.
6975 * <script type="text/javascript">
6980 * @class Roo.data.SortTypes
6982 * Defines the default sorting (casting?) comparison functions used when sorting data.
6984 Roo.data.SortTypes = {
6986 * Default sort that does nothing
6987 * @param {Mixed} s The value being converted
6988 * @return {Mixed} The comparison value
6995 * The regular expression used to strip tags
6999 stripTagsRE : /<\/?[^>]+>/gi,
7002 * Strips all HTML tags to sort on text only
7003 * @param {Mixed} s The value being converted
7004 * @return {String} The comparison value
7006 asText : function(s){
7007 return String(s).replace(this.stripTagsRE, "");
7011 * Strips all HTML tags to sort on text only - Case insensitive
7012 * @param {Mixed} s The value being converted
7013 * @return {String} The comparison value
7015 asUCText : function(s){
7016 return String(s).toUpperCase().replace(this.stripTagsRE, "");
7020 * Case insensitive string
7021 * @param {Mixed} s The value being converted
7022 * @return {String} The comparison value
7024 asUCString : function(s) {
7025 return String(s).toUpperCase();
7030 * @param {Mixed} s The value being converted
7031 * @return {Number} The comparison value
7033 asDate : function(s) {
7037 if(s instanceof Date){
7040 return Date.parse(String(s));
7045 * @param {Mixed} s The value being converted
7046 * @return {Float} The comparison value
7048 asFloat : function(s) {
7049 var val = parseFloat(String(s).replace(/,/g, ""));
7050 if(isNaN(val)) val = 0;
7056 * @param {Mixed} s The value being converted
7057 * @return {Number} The comparison value
7059 asInt : function(s) {
7060 var val = parseInt(String(s).replace(/,/g, ""));
7061 if(isNaN(val)) val = 0;
7066 * Ext JS Library 1.1.1
7067 * Copyright(c) 2006-2007, Ext JS, LLC.
7069 * Originally Released Under LGPL - original licence link has changed is not relivant.
7072 * <script type="text/javascript">
7076 * @class Roo.data.Record
7077 * Instances of this class encapsulate both record <em>definition</em> information, and record
7078 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
7079 * to access Records cached in an {@link Roo.data.Store} object.<br>
7081 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
7082 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
7085 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
7087 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
7088 * {@link #create}. The parameters are the same.
7089 * @param {Array} data An associative Array of data values keyed by the field name.
7090 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
7091 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
7092 * not specified an integer id is generated.
7094 Roo.data.Record = function(data, id){
7095 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
7100 * Generate a constructor for a specific record layout.
7101 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
7102 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
7103 * Each field definition object may contain the following properties: <ul>
7104 * <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,
7105 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
7106 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
7107 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
7108 * is being used, then this is a string containing the javascript expression to reference the data relative to
7109 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
7110 * to the data item relative to the record element. If the mapping expression is the same as the field name,
7111 * this may be omitted.</p></li>
7112 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
7113 * <ul><li>auto (Default, implies no conversion)</li>
7118 * <li>date</li></ul></p></li>
7119 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
7120 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
7121 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
7122 * by the Reader into an object that will be stored in the Record. It is passed the
7123 * following parameters:<ul>
7124 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
7126 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
7128 * <br>usage:<br><pre><code>
7129 var TopicRecord = Roo.data.Record.create(
7130 {name: 'title', mapping: 'topic_title'},
7131 {name: 'author', mapping: 'username'},
7132 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
7133 {name: 'lastPost', mapping: 'post_time', type: 'date'},
7134 {name: 'lastPoster', mapping: 'user2'},
7135 {name: 'excerpt', mapping: 'post_text'}
7138 var myNewRecord = new TopicRecord({
7139 title: 'Do my job please',
7142 lastPost: new Date(),
7143 lastPoster: 'Animal',
7144 excerpt: 'No way dude!'
7146 myStore.add(myNewRecord);
7151 Roo.data.Record.create = function(o){
7153 f.superclass.constructor.apply(this, arguments);
7155 Roo.extend(f, Roo.data.Record);
7156 var p = f.prototype;
7157 p.fields = new Roo.util.MixedCollection(false, function(field){
7160 for(var i = 0, len = o.length; i < len; i++){
7161 p.fields.add(new Roo.data.Field(o[i]));
7163 f.getField = function(name){
7164 return p.fields.get(name);
7169 Roo.data.Record.AUTO_ID = 1000;
7170 Roo.data.Record.EDIT = 'edit';
7171 Roo.data.Record.REJECT = 'reject';
7172 Roo.data.Record.COMMIT = 'commit';
7174 Roo.data.Record.prototype = {
7176 * Readonly flag - true if this record has been modified.
7185 join : function(store){
7190 * Set the named field to the specified value.
7191 * @param {String} name The name of the field to set.
7192 * @param {Object} value The value to set the field to.
7194 set : function(name, value){
7195 if(this.data[name] == value){
7202 if(typeof this.modified[name] == 'undefined'){
7203 this.modified[name] = this.data[name];
7205 this.data[name] = value;
7206 if(!this.editing && this.store){
7207 this.store.afterEdit(this);
7212 * Get the value of the named field.
7213 * @param {String} name The name of the field to get the value of.
7214 * @return {Object} The value of the field.
7216 get : function(name){
7217 return this.data[name];
7221 beginEdit : function(){
7222 this.editing = true;
7227 cancelEdit : function(){
7228 this.editing = false;
7229 delete this.modified;
7233 endEdit : function(){
7234 this.editing = false;
7235 if(this.dirty && this.store){
7236 this.store.afterEdit(this);
7241 * Usually called by the {@link Roo.data.Store} which owns the Record.
7242 * Rejects all changes made to the Record since either creation, or the last commit operation.
7243 * Modified fields are reverted to their original values.
7245 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
7246 * of reject operations.
7248 reject : function(){
7249 var m = this.modified;
7251 if(typeof m[n] != "function"){
7252 this.data[n] = m[n];
7256 delete this.modified;
7257 this.editing = false;
7259 this.store.afterReject(this);
7264 * Usually called by the {@link Roo.data.Store} which owns the Record.
7265 * Commits all changes made to the Record since either creation, or the last commit operation.
7267 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
7268 * of commit operations.
7270 commit : function(){
7272 delete this.modified;
7273 this.editing = false;
7275 this.store.afterCommit(this);
7280 hasError : function(){
7281 return this.error != null;
7285 clearError : function(){
7290 * Creates a copy of this record.
7291 * @param {String} id (optional) A new record id if you don't want to use this record's id
7294 copy : function(newId) {
7295 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
7299 * Ext JS Library 1.1.1
7300 * Copyright(c) 2006-2007, Ext JS, LLC.
7302 * Originally Released Under LGPL - original licence link has changed is not relivant.
7305 * <script type="text/javascript">
7311 * @class Roo.data.Store
7312 * @extends Roo.util.Observable
7313 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
7314 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
7316 * 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
7317 * has no knowledge of the format of the data returned by the Proxy.<br>
7319 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
7320 * instances from the data object. These records are cached and made available through accessor functions.
7322 * Creates a new Store.
7323 * @param {Object} config A config object containing the objects needed for the Store to access data,
7324 * and read the data into Records.
7326 Roo.data.Store = function(config){
7327 this.data = new Roo.util.MixedCollection(false);
7328 this.data.getKey = function(o){
7331 this.baseParams = {};
7338 "multisort" : "_multisort"
7341 if(config && config.data){
7342 this.inlineData = config.data;
7346 Roo.apply(this, config);
7348 if(this.reader){ // reader passed
7349 this.reader = Roo.factory(this.reader, Roo.data);
7350 this.reader.xmodule = this.xmodule || false;
7351 if(!this.recordType){
7352 this.recordType = this.reader.recordType;
7354 if(this.reader.onMetaChange){
7355 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
7359 if(this.recordType){
7360 this.fields = this.recordType.prototype.fields;
7366 * @event datachanged
7367 * Fires when the data cache has changed, and a widget which is using this Store
7368 * as a Record cache should refresh its view.
7369 * @param {Store} this
7374 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
7375 * @param {Store} this
7376 * @param {Object} meta The JSON metadata
7381 * Fires when Records have been added to the Store
7382 * @param {Store} this
7383 * @param {Roo.data.Record[]} records The array of Records added
7384 * @param {Number} index The index at which the record(s) were added
7389 * Fires when a Record has been removed from the Store
7390 * @param {Store} this
7391 * @param {Roo.data.Record} record The Record that was removed
7392 * @param {Number} index The index at which the record was removed
7397 * Fires when a Record has been updated
7398 * @param {Store} this
7399 * @param {Roo.data.Record} record The Record that was updated
7400 * @param {String} operation The update operation being performed. Value may be one of:
7402 Roo.data.Record.EDIT
7403 Roo.data.Record.REJECT
7404 Roo.data.Record.COMMIT
7410 * Fires when the data cache has been cleared.
7411 * @param {Store} this
7416 * Fires before a request is made for a new data object. If the beforeload handler returns false
7417 * the load action will be canceled.
7418 * @param {Store} this
7419 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7423 * @event beforeloadadd
7424 * Fires after a new set of Records has been loaded.
7425 * @param {Store} this
7426 * @param {Roo.data.Record[]} records The Records that were loaded
7427 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7429 beforeloadadd : true,
7432 * Fires after a new set of Records has been loaded, before they are added to the store.
7433 * @param {Store} this
7434 * @param {Roo.data.Record[]} records The Records that were loaded
7435 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7436 * @params {Object} return from reader
7440 * @event loadexception
7441 * Fires if an exception occurs in the Proxy during loading.
7442 * Called with the signature of the Proxy's "loadexception" event.
7443 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
7446 * @param {Object} return from JsonData.reader() - success, totalRecords, records
7447 * @param {Object} load options
7448 * @param {Object} jsonData from your request (normally this contains the Exception)
7450 loadexception : true
7454 this.proxy = Roo.factory(this.proxy, Roo.data);
7455 this.proxy.xmodule = this.xmodule || false;
7456 this.relayEvents(this.proxy, ["loadexception"]);
7458 this.sortToggle = {};
7459 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
7461 Roo.data.Store.superclass.constructor.call(this);
7463 if(this.inlineData){
7464 this.loadData(this.inlineData);
7465 delete this.inlineData;
7469 Roo.extend(Roo.data.Store, Roo.util.Observable, {
7471 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
7472 * without a remote query - used by combo/forms at present.
7476 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
7479 * @cfg {Array} data Inline data to be loaded when the store is initialized.
7482 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
7483 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
7486 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
7487 * on any HTTP request
7490 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
7493 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
7497 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
7498 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
7503 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
7504 * loaded or when a record is removed. (defaults to false).
7506 pruneModifiedRecords : false,
7512 * Add Records to the Store and fires the add event.
7513 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
7515 add : function(records){
7516 records = [].concat(records);
7517 for(var i = 0, len = records.length; i < len; i++){
7518 records[i].join(this);
7520 var index = this.data.length;
7521 this.data.addAll(records);
7522 this.fireEvent("add", this, records, index);
7526 * Remove a Record from the Store and fires the remove event.
7527 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
7529 remove : function(record){
7530 var index = this.data.indexOf(record);
7531 this.data.removeAt(index);
7532 if(this.pruneModifiedRecords){
7533 this.modified.remove(record);
7535 this.fireEvent("remove", this, record, index);
7539 * Remove all Records from the Store and fires the clear event.
7541 removeAll : function(){
7543 if(this.pruneModifiedRecords){
7546 this.fireEvent("clear", this);
7550 * Inserts Records to the Store at the given index and fires the add event.
7551 * @param {Number} index The start index at which to insert the passed Records.
7552 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
7554 insert : function(index, records){
7555 records = [].concat(records);
7556 for(var i = 0, len = records.length; i < len; i++){
7557 this.data.insert(index, records[i]);
7558 records[i].join(this);
7560 this.fireEvent("add", this, records, index);
7564 * Get the index within the cache of the passed Record.
7565 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
7566 * @return {Number} The index of the passed Record. Returns -1 if not found.
7568 indexOf : function(record){
7569 return this.data.indexOf(record);
7573 * Get the index within the cache of the Record with the passed id.
7574 * @param {String} id The id of the Record to find.
7575 * @return {Number} The index of the Record. Returns -1 if not found.
7577 indexOfId : function(id){
7578 return this.data.indexOfKey(id);
7582 * Get the Record with the specified id.
7583 * @param {String} id The id of the Record to find.
7584 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
7586 getById : function(id){
7587 return this.data.key(id);
7591 * Get the Record at the specified index.
7592 * @param {Number} index The index of the Record to find.
7593 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
7595 getAt : function(index){
7596 return this.data.itemAt(index);
7600 * Returns a range of Records between specified indices.
7601 * @param {Number} startIndex (optional) The starting index (defaults to 0)
7602 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
7603 * @return {Roo.data.Record[]} An array of Records
7605 getRange : function(start, end){
7606 return this.data.getRange(start, end);
7610 storeOptions : function(o){
7611 o = Roo.apply({}, o);
7614 this.lastOptions = o;
7618 * Loads the Record cache from the configured Proxy using the configured Reader.
7620 * If using remote paging, then the first load call must specify the <em>start</em>
7621 * and <em>limit</em> properties in the options.params property to establish the initial
7622 * position within the dataset, and the number of Records to cache on each read from the Proxy.
7624 * <strong>It is important to note that for remote data sources, loading is asynchronous,
7625 * and this call will return before the new data has been loaded. Perform any post-processing
7626 * in a callback function, or in a "load" event handler.</strong>
7628 * @param {Object} options An object containing properties which control loading options:<ul>
7629 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
7630 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
7631 * passed the following arguments:<ul>
7632 * <li>r : Roo.data.Record[]</li>
7633 * <li>options: Options object from the load call</li>
7634 * <li>success: Boolean success indicator</li></ul></li>
7635 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
7636 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
7639 load : function(options){
7640 options = options || {};
7641 if(this.fireEvent("beforeload", this, options) !== false){
7642 this.storeOptions(options);
7643 var p = Roo.apply(options.params || {}, this.baseParams);
7644 // if meta was not loaded from remote source.. try requesting it.
7645 if (!this.reader.metaFromRemote) {
7648 if(this.sortInfo && this.remoteSort){
7649 var pn = this.paramNames;
7650 p[pn["sort"]] = this.sortInfo.field;
7651 p[pn["dir"]] = this.sortInfo.direction;
7653 if (this.multiSort) {
7654 var pn = this.paramNames;
7655 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
7658 this.proxy.load(p, this.reader, this.loadRecords, this, options);
7663 * Reloads the Record cache from the configured Proxy using the configured Reader and
7664 * the options from the last load operation performed.
7665 * @param {Object} options (optional) An object containing properties which may override the options
7666 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
7667 * the most recently used options are reused).
7669 reload : function(options){
7670 this.load(Roo.applyIf(options||{}, this.lastOptions));
7674 // Called as a callback by the Reader during a load operation.
7675 loadRecords : function(o, options, success){
7676 if(!o || success === false){
7677 if(success !== false){
7678 this.fireEvent("load", this, [], options, o);
7680 if(options.callback){
7681 options.callback.call(options.scope || this, [], options, false);
7685 // if data returned failure - throw an exception.
7686 if (o.success === false) {
7687 // show a message if no listener is registered.
7688 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
7689 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
7691 // loadmask wil be hooked into this..
7692 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
7695 var r = o.records, t = o.totalRecords || r.length;
7697 this.fireEvent("beforeloadadd", this, r, options, o);
7699 if(!options || options.add !== true){
7700 if(this.pruneModifiedRecords){
7703 for(var i = 0, len = r.length; i < len; i++){
7707 this.data = this.snapshot;
7708 delete this.snapshot;
7711 this.data.addAll(r);
7712 this.totalLength = t;
7714 this.fireEvent("datachanged", this);
7716 this.totalLength = Math.max(t, this.data.length+r.length);
7719 this.fireEvent("load", this, r, options, o);
7720 if(options.callback){
7721 options.callback.call(options.scope || this, r, options, true);
7727 * Loads data from a passed data block. A Reader which understands the format of the data
7728 * must have been configured in the constructor.
7729 * @param {Object} data The data block from which to read the Records. The format of the data expected
7730 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
7731 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
7733 loadData : function(o, append){
7734 var r = this.reader.readRecords(o);
7735 this.loadRecords(r, {add: append}, true);
7739 * Gets the number of cached records.
7741 * <em>If using paging, this may not be the total size of the dataset. If the data object
7742 * used by the Reader contains the dataset size, then the getTotalCount() function returns
7743 * the data set size</em>
7745 getCount : function(){
7746 return this.data.length || 0;
7750 * Gets the total number of records in the dataset as returned by the server.
7752 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
7753 * the dataset size</em>
7755 getTotalCount : function(){
7756 return this.totalLength || 0;
7760 * Returns the sort state of the Store as an object with two properties:
7762 field {String} The name of the field by which the Records are sorted
7763 direction {String} The sort order, "ASC" or "DESC"
7766 getSortState : function(){
7767 return this.sortInfo;
7771 applySort : function(){
7772 if(this.sortInfo && !this.remoteSort){
7773 var s = this.sortInfo, f = s.field;
7774 var st = this.fields.get(f).sortType;
7775 var fn = function(r1, r2){
7776 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
7777 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
7779 this.data.sort(s.direction, fn);
7780 if(this.snapshot && this.snapshot != this.data){
7781 this.snapshot.sort(s.direction, fn);
7787 * Sets the default sort column and order to be used by the next load operation.
7788 * @param {String} fieldName The name of the field to sort by.
7789 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
7791 setDefaultSort : function(field, dir){
7792 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
7797 * If remote sorting is used, the sort is performed on the server, and the cache is
7798 * reloaded. If local sorting is used, the cache is sorted internally.
7799 * @param {String} fieldName The name of the field to sort by.
7800 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
7802 sort : function(fieldName, dir){
7803 var f = this.fields.get(fieldName);
7805 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
7807 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
7808 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
7813 this.sortToggle[f.name] = dir;
7814 this.sortInfo = {field: f.name, direction: dir};
7815 if(!this.remoteSort){
7817 this.fireEvent("datachanged", this);
7819 this.load(this.lastOptions);
7824 * Calls the specified function for each of the Records in the cache.
7825 * @param {Function} fn The function to call. The Record is passed as the first parameter.
7826 * Returning <em>false</em> aborts and exits the iteration.
7827 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
7829 each : function(fn, scope){
7830 this.data.each(fn, scope);
7834 * Gets all records modified since the last commit. Modified records are persisted across load operations
7835 * (e.g., during paging).
7836 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
7838 getModifiedRecords : function(){
7839 return this.modified;
7843 createFilterFn : function(property, value, anyMatch){
7844 if(!value.exec){ // not a regex
7845 value = String(value);
7846 if(value.length == 0){
7849 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
7852 return value.test(r.data[property]);
7857 * Sums the value of <i>property</i> for each record between start and end and returns the result.
7858 * @param {String} property A field on your records
7859 * @param {Number} start The record index to start at (defaults to 0)
7860 * @param {Number} end The last record index to include (defaults to length - 1)
7861 * @return {Number} The sum
7863 sum : function(property, start, end){
7864 var rs = this.data.items, v = 0;
7866 end = (end || end === 0) ? end : rs.length-1;
7868 for(var i = start; i <= end; i++){
7869 v += (rs[i].data[property] || 0);
7875 * Filter the records by a specified property.
7876 * @param {String} field A field on your records
7877 * @param {String/RegExp} value Either a string that the field
7878 * should start with or a RegExp to test against the field
7879 * @param {Boolean} anyMatch True to match any part not just the beginning
7881 filter : function(property, value, anyMatch){
7882 var fn = this.createFilterFn(property, value, anyMatch);
7883 return fn ? this.filterBy(fn) : this.clearFilter();
7887 * Filter by a function. The specified function will be called with each
7888 * record in this data source. If the function returns true the record is included,
7889 * otherwise it is filtered.
7890 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
7891 * @param {Object} scope (optional) The scope of the function (defaults to this)
7893 filterBy : function(fn, scope){
7894 this.snapshot = this.snapshot || this.data;
7895 this.data = this.queryBy(fn, scope||this);
7896 this.fireEvent("datachanged", this);
7900 * Query the records by a specified property.
7901 * @param {String} field A field on your records
7902 * @param {String/RegExp} value Either a string that the field
7903 * should start with or a RegExp to test against the field
7904 * @param {Boolean} anyMatch True to match any part not just the beginning
7905 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
7907 query : function(property, value, anyMatch){
7908 var fn = this.createFilterFn(property, value, anyMatch);
7909 return fn ? this.queryBy(fn) : this.data.clone();
7913 * Query by a function. The specified function will be called with each
7914 * record in this data source. If the function returns true the record is included
7916 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
7917 * @param {Object} scope (optional) The scope of the function (defaults to this)
7918 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
7920 queryBy : function(fn, scope){
7921 var data = this.snapshot || this.data;
7922 return data.filterBy(fn, scope||this);
7926 * Collects unique values for a particular dataIndex from this store.
7927 * @param {String} dataIndex The property to collect
7928 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
7929 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
7930 * @return {Array} An array of the unique values
7932 collect : function(dataIndex, allowNull, bypassFilter){
7933 var d = (bypassFilter === true && this.snapshot) ?
7934 this.snapshot.items : this.data.items;
7935 var v, sv, r = [], l = {};
7936 for(var i = 0, len = d.length; i < len; i++){
7937 v = d[i].data[dataIndex];
7939 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
7948 * Revert to a view of the Record cache with no filtering applied.
7949 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
7951 clearFilter : function(suppressEvent){
7952 if(this.snapshot && this.snapshot != this.data){
7953 this.data = this.snapshot;
7954 delete this.snapshot;
7955 if(suppressEvent !== true){
7956 this.fireEvent("datachanged", this);
7962 afterEdit : function(record){
7963 if(this.modified.indexOf(record) == -1){
7964 this.modified.push(record);
7966 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
7970 afterReject : function(record){
7971 this.modified.remove(record);
7972 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
7976 afterCommit : function(record){
7977 this.modified.remove(record);
7978 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
7982 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
7983 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
7985 commitChanges : function(){
7986 var m = this.modified.slice(0);
7988 for(var i = 0, len = m.length; i < len; i++){
7994 * Cancel outstanding changes on all changed records.
7996 rejectChanges : function(){
7997 var m = this.modified.slice(0);
7999 for(var i = 0, len = m.length; i < len; i++){
8004 onMetaChange : function(meta, rtype, o){
8005 this.recordType = rtype;
8006 this.fields = rtype.prototype.fields;
8007 delete this.snapshot;
8008 this.sortInfo = meta.sortInfo || this.sortInfo;
8010 this.fireEvent('metachange', this, this.reader.meta);
8013 moveIndex : function(data, type)
8015 var index = this.indexOf(data);
8017 var newIndex = index + type;
8021 this.insert(newIndex, data);
8026 * Ext JS Library 1.1.1
8027 * Copyright(c) 2006-2007, Ext JS, LLC.
8029 * Originally Released Under LGPL - original licence link has changed is not relivant.
8032 * <script type="text/javascript">
8036 * @class Roo.data.SimpleStore
8037 * @extends Roo.data.Store
8038 * Small helper class to make creating Stores from Array data easier.
8039 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
8040 * @cfg {Array} fields An array of field definition objects, or field name strings.
8041 * @cfg {Array} data The multi-dimensional array of data
8043 * @param {Object} config
8045 Roo.data.SimpleStore = function(config){
8046 Roo.data.SimpleStore.superclass.constructor.call(this, {
8048 reader: new Roo.data.ArrayReader({
8051 Roo.data.Record.create(config.fields)
8053 proxy : new Roo.data.MemoryProxy(config.data)
8057 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
8059 * Ext JS Library 1.1.1
8060 * Copyright(c) 2006-2007, Ext JS, LLC.
8062 * Originally Released Under LGPL - original licence link has changed is not relivant.
8065 * <script type="text/javascript">
8070 * @extends Roo.data.Store
8071 * @class Roo.data.JsonStore
8072 * Small helper class to make creating Stores for JSON data easier. <br/>
8074 var store = new Roo.data.JsonStore({
8075 url: 'get-images.php',
8077 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
8080 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
8081 * JsonReader and HttpProxy (unless inline data is provided).</b>
8082 * @cfg {Array} fields An array of field definition objects, or field name strings.
8084 * @param {Object} config
8086 Roo.data.JsonStore = function(c){
8087 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
8088 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
8089 reader: new Roo.data.JsonReader(c, c.fields)
8092 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
8094 * Ext JS Library 1.1.1
8095 * Copyright(c) 2006-2007, Ext JS, LLC.
8097 * Originally Released Under LGPL - original licence link has changed is not relivant.
8100 * <script type="text/javascript">
8104 Roo.data.Field = function(config){
8105 if(typeof config == "string"){
8106 config = {name: config};
8108 Roo.apply(this, config);
8114 var st = Roo.data.SortTypes;
8115 // named sortTypes are supported, here we look them up
8116 if(typeof this.sortType == "string"){
8117 this.sortType = st[this.sortType];
8120 // set default sortType for strings and dates
8124 this.sortType = st.asUCString;
8127 this.sortType = st.asDate;
8130 this.sortType = st.none;
8135 var stripRe = /[\$,%]/g;
8137 // prebuilt conversion function for this field, instead of
8138 // switching every time we're reading a value
8140 var cv, dateFormat = this.dateFormat;
8145 cv = function(v){ return v; };
8148 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
8152 return v !== undefined && v !== null && v !== '' ?
8153 parseInt(String(v).replace(stripRe, ""), 10) : '';
8158 return v !== undefined && v !== null && v !== '' ?
8159 parseFloat(String(v).replace(stripRe, ""), 10) : '';
8164 cv = function(v){ return v === true || v === "true" || v == 1; };
8171 if(v instanceof Date){
8175 if(dateFormat == "timestamp"){
8176 return new Date(v*1000);
8178 return Date.parseDate(v, dateFormat);
8180 var parsed = Date.parse(v);
8181 return parsed ? new Date(parsed) : null;
8190 Roo.data.Field.prototype = {
8198 * Ext JS Library 1.1.1
8199 * Copyright(c) 2006-2007, Ext JS, LLC.
8201 * Originally Released Under LGPL - original licence link has changed is not relivant.
8204 * <script type="text/javascript">
8207 // Base class for reading structured data from a data source. This class is intended to be
8208 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
8211 * @class Roo.data.DataReader
8212 * Base class for reading structured data from a data source. This class is intended to be
8213 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
8216 Roo.data.DataReader = function(meta, recordType){
8220 this.recordType = recordType instanceof Array ?
8221 Roo.data.Record.create(recordType) : recordType;
8224 Roo.data.DataReader.prototype = {
8226 * Create an empty record
8227 * @param {Object} data (optional) - overlay some values
8228 * @return {Roo.data.Record} record created.
8230 newRow : function(d) {
8232 this.recordType.prototype.fields.each(function(c) {
8234 case 'int' : da[c.name] = 0; break;
8235 case 'date' : da[c.name] = new Date(); break;
8236 case 'float' : da[c.name] = 0.0; break;
8237 case 'boolean' : da[c.name] = false; break;
8238 default : da[c.name] = ""; break;
8242 return new this.recordType(Roo.apply(da, d));
8247 * Ext JS Library 1.1.1
8248 * Copyright(c) 2006-2007, Ext JS, LLC.
8250 * Originally Released Under LGPL - original licence link has changed is not relivant.
8253 * <script type="text/javascript">
8257 * @class Roo.data.DataProxy
8258 * @extends Roo.data.Observable
8259 * This class is an abstract base class for implementations which provide retrieval of
8260 * unformatted data objects.<br>
8262 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
8263 * (of the appropriate type which knows how to parse the data object) to provide a block of
8264 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
8266 * Custom implementations must implement the load method as described in
8267 * {@link Roo.data.HttpProxy#load}.
8269 Roo.data.DataProxy = function(){
8273 * Fires before a network request is made to retrieve a data object.
8274 * @param {Object} This DataProxy object.
8275 * @param {Object} params The params parameter to the load function.
8280 * Fires before the load method's callback is called.
8281 * @param {Object} This DataProxy object.
8282 * @param {Object} o The data object.
8283 * @param {Object} arg The callback argument object passed to the load function.
8287 * @event loadexception
8288 * Fires if an Exception occurs during data retrieval.
8289 * @param {Object} This DataProxy object.
8290 * @param {Object} o The data object.
8291 * @param {Object} arg The callback argument object passed to the load function.
8292 * @param {Object} e The Exception.
8294 loadexception : true
8296 Roo.data.DataProxy.superclass.constructor.call(this);
8299 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
8302 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
8306 * Ext JS Library 1.1.1
8307 * Copyright(c) 2006-2007, Ext JS, LLC.
8309 * Originally Released Under LGPL - original licence link has changed is not relivant.
8312 * <script type="text/javascript">
8315 * @class Roo.data.MemoryProxy
8316 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
8317 * to the Reader when its load method is called.
8319 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
8321 Roo.data.MemoryProxy = function(data){
8325 Roo.data.MemoryProxy.superclass.constructor.call(this);
8329 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
8331 * Load data from the requested source (in this case an in-memory
8332 * data object passed to the constructor), read the data object into
8333 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
8334 * process that block using the passed callback.
8335 * @param {Object} params This parameter is not used by the MemoryProxy class.
8336 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8337 * object into a block of Roo.data.Records.
8338 * @param {Function} callback The function into which to pass the block of Roo.data.records.
8339 * The function must be passed <ul>
8340 * <li>The Record block object</li>
8341 * <li>The "arg" argument from the load function</li>
8342 * <li>A boolean success indicator</li>
8344 * @param {Object} scope The scope in which to call the callback
8345 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8347 load : function(params, reader, callback, scope, arg){
8348 params = params || {};
8351 result = reader.readRecords(this.data);
8353 this.fireEvent("loadexception", this, arg, null, e);
8354 callback.call(scope, null, arg, false);
8357 callback.call(scope, result, arg, true);
8361 update : function(params, records){
8366 * Ext JS Library 1.1.1
8367 * Copyright(c) 2006-2007, Ext JS, LLC.
8369 * Originally Released Under LGPL - original licence link has changed is not relivant.
8372 * <script type="text/javascript">
8375 * @class Roo.data.HttpProxy
8376 * @extends Roo.data.DataProxy
8377 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
8378 * configured to reference a certain URL.<br><br>
8380 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
8381 * from which the running page was served.<br><br>
8383 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
8385 * Be aware that to enable the browser to parse an XML document, the server must set
8386 * the Content-Type header in the HTTP response to "text/xml".
8388 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
8389 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
8390 * will be used to make the request.
8392 Roo.data.HttpProxy = function(conn){
8393 Roo.data.HttpProxy.superclass.constructor.call(this);
8394 // is conn a conn config or a real conn?
8396 this.useAjax = !conn || !conn.events;
8400 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
8401 // thse are take from connection...
8404 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
8407 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
8408 * extra parameters to each request made by this object. (defaults to undefined)
8411 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
8412 * to each request made by this object. (defaults to undefined)
8415 * @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)
8418 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
8421 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
8427 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
8431 * Return the {@link Roo.data.Connection} object being used by this Proxy.
8432 * @return {Connection} The Connection object. This object may be used to subscribe to events on
8433 * a finer-grained basis than the DataProxy events.
8435 getConnection : function(){
8436 return this.useAjax ? Roo.Ajax : this.conn;
8440 * Load data from the configured {@link Roo.data.Connection}, read the data object into
8441 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
8442 * process that block using the passed callback.
8443 * @param {Object} params An object containing properties which are to be used as HTTP parameters
8444 * for the request to the remote server.
8445 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8446 * object into a block of Roo.data.Records.
8447 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
8448 * The function must be passed <ul>
8449 * <li>The Record block object</li>
8450 * <li>The "arg" argument from the load function</li>
8451 * <li>A boolean success indicator</li>
8453 * @param {Object} scope The scope in which to call the callback
8454 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8456 load : function(params, reader, callback, scope, arg){
8457 if(this.fireEvent("beforeload", this, params) !== false){
8459 params : params || {},
8461 callback : callback,
8466 callback : this.loadResponse,
8470 Roo.applyIf(o, this.conn);
8471 if(this.activeRequest){
8472 Roo.Ajax.abort(this.activeRequest);
8474 this.activeRequest = Roo.Ajax.request(o);
8476 this.conn.request(o);
8479 callback.call(scope||this, null, arg, false);
8484 loadResponse : function(o, success, response){
8485 delete this.activeRequest;
8487 this.fireEvent("loadexception", this, o, response);
8488 o.request.callback.call(o.request.scope, null, o.request.arg, false);
8493 result = o.reader.read(response);
8495 this.fireEvent("loadexception", this, o, response, e);
8496 o.request.callback.call(o.request.scope, null, o.request.arg, false);
8500 this.fireEvent("load", this, o, o.request.arg);
8501 o.request.callback.call(o.request.scope, result, o.request.arg, true);
8505 update : function(dataSet){
8510 updateResponse : function(dataSet){
8515 * Ext JS Library 1.1.1
8516 * Copyright(c) 2006-2007, Ext JS, LLC.
8518 * Originally Released Under LGPL - original licence link has changed is not relivant.
8521 * <script type="text/javascript">
8525 * @class Roo.data.ScriptTagProxy
8526 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
8527 * other than the originating domain of the running page.<br><br>
8529 * <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
8530 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
8532 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
8533 * source code that is used as the source inside a <script> tag.<br><br>
8535 * In order for the browser to process the returned data, the server must wrap the data object
8536 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
8537 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
8538 * depending on whether the callback name was passed:
8541 boolean scriptTag = false;
8542 String cb = request.getParameter("callback");
8545 response.setContentType("text/javascript");
8547 response.setContentType("application/x-json");
8549 Writer out = response.getWriter();
8551 out.write(cb + "(");
8553 out.print(dataBlock.toJsonString());
8560 * @param {Object} config A configuration object.
8562 Roo.data.ScriptTagProxy = function(config){
8563 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
8564 Roo.apply(this, config);
8565 this.head = document.getElementsByTagName("head")[0];
8568 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
8570 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
8572 * @cfg {String} url The URL from which to request the data object.
8575 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
8579 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
8580 * the server the name of the callback function set up by the load call to process the returned data object.
8581 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
8582 * javascript output which calls this named function passing the data object as its only parameter.
8584 callbackParam : "callback",
8586 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
8587 * name to the request.
8592 * Load data from the configured URL, read the data object into
8593 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
8594 * process that block using the passed callback.
8595 * @param {Object} params An object containing properties which are to be used as HTTP parameters
8596 * for the request to the remote server.
8597 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8598 * object into a block of Roo.data.Records.
8599 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
8600 * The function must be passed <ul>
8601 * <li>The Record block object</li>
8602 * <li>The "arg" argument from the load function</li>
8603 * <li>A boolean success indicator</li>
8605 * @param {Object} scope The scope in which to call the callback
8606 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8608 load : function(params, reader, callback, scope, arg){
8609 if(this.fireEvent("beforeload", this, params) !== false){
8611 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
8614 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
8616 url += "&_dc=" + (new Date().getTime());
8618 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
8621 cb : "stcCallback"+transId,
8622 scriptId : "stcScript"+transId,
8626 callback : callback,
8632 window[trans.cb] = function(o){
8633 conn.handleResponse(o, trans);
8636 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
8638 if(this.autoAbort !== false){
8642 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
8644 var script = document.createElement("script");
8645 script.setAttribute("src", url);
8646 script.setAttribute("type", "text/javascript");
8647 script.setAttribute("id", trans.scriptId);
8648 this.head.appendChild(script);
8652 callback.call(scope||this, null, arg, false);
8657 isLoading : function(){
8658 return this.trans ? true : false;
8662 * Abort the current server request.
8665 if(this.isLoading()){
8666 this.destroyTrans(this.trans);
8671 destroyTrans : function(trans, isLoaded){
8672 this.head.removeChild(document.getElementById(trans.scriptId));
8673 clearTimeout(trans.timeoutId);
8675 window[trans.cb] = undefined;
8677 delete window[trans.cb];
8680 // if hasn't been loaded, wait for load to remove it to prevent script error
8681 window[trans.cb] = function(){
8682 window[trans.cb] = undefined;
8684 delete window[trans.cb];
8691 handleResponse : function(o, trans){
8693 this.destroyTrans(trans, true);
8696 result = trans.reader.readRecords(o);
8698 this.fireEvent("loadexception", this, o, trans.arg, e);
8699 trans.callback.call(trans.scope||window, null, trans.arg, false);
8702 this.fireEvent("load", this, o, trans.arg);
8703 trans.callback.call(trans.scope||window, result, trans.arg, true);
8707 handleFailure : function(trans){
8709 this.destroyTrans(trans, false);
8710 this.fireEvent("loadexception", this, null, trans.arg);
8711 trans.callback.call(trans.scope||window, null, trans.arg, false);
8715 * Ext JS Library 1.1.1
8716 * Copyright(c) 2006-2007, Ext JS, LLC.
8718 * Originally Released Under LGPL - original licence link has changed is not relivant.
8721 * <script type="text/javascript">
8725 * @class Roo.data.JsonReader
8726 * @extends Roo.data.DataReader
8727 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
8728 * based on mappings in a provided Roo.data.Record constructor.
8730 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
8731 * in the reply previously.
8736 var RecordDef = Roo.data.Record.create([
8737 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
8738 {name: 'occupation'} // This field will use "occupation" as the mapping.
8740 var myReader = new Roo.data.JsonReader({
8741 totalProperty: "results", // The property which contains the total dataset size (optional)
8742 root: "rows", // The property which contains an Array of row objects
8743 id: "id" // The property within each row object that provides an ID for the record (optional)
8747 * This would consume a JSON file like this:
8749 { 'results': 2, 'rows': [
8750 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
8751 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
8754 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
8755 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
8756 * paged from the remote server.
8757 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
8758 * @cfg {String} root name of the property which contains the Array of row objects.
8759 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
8761 * Create a new JsonReader
8762 * @param {Object} meta Metadata configuration options
8763 * @param {Object} recordType Either an Array of field definition objects,
8764 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
8766 Roo.data.JsonReader = function(meta, recordType){
8769 // set some defaults:
8771 totalProperty: 'total',
8772 successProperty : 'success',
8777 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
8779 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
8782 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
8783 * Used by Store query builder to append _requestMeta to params.
8786 metaFromRemote : false,
8788 * This method is only used by a DataProxy which has retrieved data from a remote server.
8789 * @param {Object} response The XHR object which contains the JSON data in its responseText.
8790 * @return {Object} data A data block which is used by an Roo.data.Store object as
8791 * a cache of Roo.data.Records.
8793 read : function(response){
8794 var json = response.responseText;
8796 var o = /* eval:var:o */ eval("("+json+")");
8798 throw {message: "JsonReader.read: Json object not found"};
8804 this.metaFromRemote = true;
8805 this.meta = o.metaData;
8806 this.recordType = Roo.data.Record.create(o.metaData.fields);
8807 this.onMetaChange(this.meta, this.recordType, o);
8809 return this.readRecords(o);
8812 // private function a store will implement
8813 onMetaChange : function(meta, recordType, o){
8820 simpleAccess: function(obj, subsc) {
8827 getJsonAccessor: function(){
8829 return function(expr) {
8831 return(re.test(expr))
8832 ? new Function("obj", "return obj." + expr)
8842 * Create a data block containing Roo.data.Records from an XML document.
8843 * @param {Object} o An object which contains an Array of row objects in the property specified
8844 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
8845 * which contains the total size of the dataset.
8846 * @return {Object} data A data block which is used by an Roo.data.Store object as
8847 * a cache of Roo.data.Records.
8849 readRecords : function(o){
8851 * After any data loads, the raw JSON data is available for further custom processing.
8855 var s = this.meta, Record = this.recordType,
8856 f = Record.prototype.fields, fi = f.items, fl = f.length;
8858 // Generate extraction functions for the totalProperty, the root, the id, and for each field
8860 if(s.totalProperty) {
8861 this.getTotal = this.getJsonAccessor(s.totalProperty);
8863 if(s.successProperty) {
8864 this.getSuccess = this.getJsonAccessor(s.successProperty);
8866 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
8868 var g = this.getJsonAccessor(s.id);
8869 this.getId = function(rec) {
8871 return (r === undefined || r === "") ? null : r;
8874 this.getId = function(){return null;};
8877 for(var jj = 0; jj < fl; jj++){
8879 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
8880 this.ef[jj] = this.getJsonAccessor(map);
8884 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
8885 if(s.totalProperty){
8886 var vt = parseInt(this.getTotal(o), 10);
8891 if(s.successProperty){
8892 var vs = this.getSuccess(o);
8893 if(vs === false || vs === 'false'){
8898 for(var i = 0; i < c; i++){
8901 var id = this.getId(n);
8902 for(var j = 0; j < fl; j++){
8904 var v = this.ef[j](n);
8906 Roo.log('missing convert for ' + f.name);
8910 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
8912 var record = new Record(values, id);
8914 records[i] = record;
8920 totalRecords : totalRecords
8925 * Ext JS Library 1.1.1
8926 * Copyright(c) 2006-2007, Ext JS, LLC.
8928 * Originally Released Under LGPL - original licence link has changed is not relivant.
8931 * <script type="text/javascript">
8935 * @class Roo.data.ArrayReader
8936 * @extends Roo.data.DataReader
8937 * Data reader class to create an Array of Roo.data.Record objects from an Array.
8938 * Each element of that Array represents a row of data fields. The
8939 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
8940 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
8944 var RecordDef = Roo.data.Record.create([
8945 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
8946 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
8948 var myReader = new Roo.data.ArrayReader({
8949 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
8953 * This would consume an Array like this:
8955 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
8957 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
8959 * Create a new JsonReader
8960 * @param {Object} meta Metadata configuration options.
8961 * @param {Object} recordType Either an Array of field definition objects
8962 * as specified to {@link Roo.data.Record#create},
8963 * or an {@link Roo.data.Record} object
8964 * created using {@link Roo.data.Record#create}.
8966 Roo.data.ArrayReader = function(meta, recordType){
8967 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
8970 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
8972 * Create a data block containing Roo.data.Records from an XML document.
8973 * @param {Object} o An Array of row objects which represents the dataset.
8974 * @return {Object} data A data block which is used by an Roo.data.Store object as
8975 * a cache of Roo.data.Records.
8977 readRecords : function(o){
8978 var sid = this.meta ? this.meta.id : null;
8979 var recordType = this.recordType, fields = recordType.prototype.fields;
8982 for(var i = 0; i < root.length; i++){
8985 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
8986 for(var j = 0, jlen = fields.length; j < jlen; j++){
8987 var f = fields.items[j];
8988 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
8989 var v = n[k] !== undefined ? n[k] : f.defaultValue;
8993 var record = new recordType(values, id);
8995 records[records.length] = record;
8999 totalRecords : records.length
9008 * @class Roo.bootstrap.ComboBox
9009 * @extends Roo.bootstrap.TriggerField
9010 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
9011 * @cfg {Boolean} append (true|false) default false
9013 * Create a new ComboBox.
9014 * @param {Object} config Configuration options
9016 Roo.bootstrap.ComboBox = function(config){
9017 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
9021 * Fires when the dropdown list is expanded
9022 * @param {Roo.bootstrap.ComboBox} combo This combo box
9027 * Fires when the dropdown list is collapsed
9028 * @param {Roo.bootstrap.ComboBox} combo This combo box
9032 * @event beforeselect
9033 * Fires before a list item is selected. Return false to cancel the selection.
9034 * @param {Roo.bootstrap.ComboBox} combo This combo box
9035 * @param {Roo.data.Record} record The data record returned from the underlying store
9036 * @param {Number} index The index of the selected item in the dropdown list
9038 'beforeselect' : true,
9041 * Fires when a list item is selected
9042 * @param {Roo.bootstrap.ComboBox} combo This combo box
9043 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
9044 * @param {Number} index The index of the selected item in the dropdown list
9048 * @event beforequery
9049 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
9050 * The event object passed has these properties:
9051 * @param {Roo.bootstrap.ComboBox} combo This combo box
9052 * @param {String} query The query
9053 * @param {Boolean} forceAll true to force "all" query
9054 * @param {Boolean} cancel true to cancel the query
9055 * @param {Object} e The query event object
9057 'beforequery': true,
9060 * Fires when the 'add' icon is pressed (add a listener to enable add button)
9061 * @param {Roo.bootstrap.ComboBox} combo This combo box
9066 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
9067 * @param {Roo.bootstrap.ComboBox} combo This combo box
9068 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
9073 * Fires when the remove value from the combobox array
9074 * @param {Roo.bootstrap.ComboBox} combo This combo box
9081 this.selectedIndex = -1;
9082 if(this.mode == 'local'){
9083 if(config.queryDelay === undefined){
9084 this.queryDelay = 10;
9086 if(config.minChars === undefined){
9092 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
9095 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
9096 * rendering into an Roo.Editor, defaults to false)
9099 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
9100 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
9103 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
9106 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
9107 * the dropdown list (defaults to undefined, with no header element)
9111 * @cfg {String/Roo.Template} tpl The template to use to render the output
9115 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
9117 listWidth: undefined,
9119 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
9120 * mode = 'remote' or 'text' if mode = 'local')
9122 displayField: undefined,
9124 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
9125 * mode = 'remote' or 'value' if mode = 'local').
9126 * Note: use of a valueField requires the user make a selection
9127 * in order for a value to be mapped.
9129 valueField: undefined,
9133 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
9134 * field's data value (defaults to the underlying DOM element's name)
9136 hiddenName: undefined,
9138 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
9142 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
9144 selectedClass: 'active',
9147 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
9151 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
9152 * anchor positions (defaults to 'tl-bl')
9154 listAlign: 'tl-bl?',
9156 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
9160 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
9161 * query specified by the allQuery config option (defaults to 'query')
9163 triggerAction: 'query',
9165 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
9166 * (defaults to 4, does not apply if editable = false)
9170 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
9171 * delay (typeAheadDelay) if it matches a known value (defaults to false)
9175 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
9176 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
9180 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
9181 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
9185 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
9186 * when editable = true (defaults to false)
9188 selectOnFocus:false,
9190 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
9192 queryParam: 'query',
9194 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
9195 * when mode = 'remote' (defaults to 'Loading...')
9197 loadingText: 'Loading...',
9199 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
9203 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
9207 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
9208 * traditional select (defaults to true)
9212 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
9216 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
9220 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
9221 * listWidth has a higher value)
9225 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
9226 * allow the user to set arbitrary text into the field (defaults to false)
9228 forceSelection:false,
9230 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
9231 * if typeAhead = true (defaults to 250)
9233 typeAheadDelay : 250,
9235 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
9236 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
9238 valueNotFoundText : undefined,
9240 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
9245 * @cfg {Boolean} disableClear Disable showing of clear button.
9247 disableClear : false,
9249 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
9251 alwaysQuery : false,
9254 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
9268 // element that contains real text value.. (when hidden is used..)
9271 initEvents: function(){
9274 throw "can not find store for combo";
9276 this.store = Roo.factory(this.store, Roo.data);
9280 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
9283 if(this.hiddenName){
9285 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
9287 this.hiddenField.dom.value =
9288 this.hiddenValue !== undefined ? this.hiddenValue :
9289 this.value !== undefined ? this.value : '';
9291 // prevent input submission
9292 this.el.dom.removeAttribute('name');
9293 this.hiddenField.dom.setAttribute('name', this.hiddenName);
9298 // this.el.dom.setAttribute('autocomplete', 'off');
9301 var cls = 'x-combo-list';
9302 this.list = this.el.select('ul.dropdown-menu',true).first();
9304 //this.list = new Roo.Layer({
9305 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
9308 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
9309 this.list.setWidth(lw);
9311 this.list.on('mouseover', this.onViewOver, this);
9312 this.list.on('mousemove', this.onViewMove, this);
9314 this.list.on('scroll', this.onViewScroll, this);
9317 this.list.swallowEvent('mousewheel');
9318 this.assetHeight = 0;
9321 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
9322 this.assetHeight += this.header.getHeight();
9325 this.innerList = this.list.createChild({cls:cls+'-inner'});
9326 this.innerList.on('mouseover', this.onViewOver, this);
9327 this.innerList.on('mousemove', this.onViewMove, this);
9328 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
9330 if(this.allowBlank && !this.pageSize && !this.disableClear){
9331 this.footer = this.list.createChild({cls:cls+'-ft'});
9332 this.pageTb = new Roo.Toolbar(this.footer);
9336 this.footer = this.list.createChild({cls:cls+'-ft'});
9337 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
9338 {pageSize: this.pageSize});
9342 if (this.pageTb && this.allowBlank && !this.disableClear) {
9344 this.pageTb.add(new Roo.Toolbar.Fill(), {
9345 cls: 'x-btn-icon x-btn-clear',
9351 _this.onSelect(false, -1);
9356 this.assetHeight += this.footer.getHeight();
9361 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
9364 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
9365 singleSelect:true, store: this.store, selectedClass: this.selectedClass
9367 //this.view.wrapEl.setDisplayed(false);
9368 this.view.on('click', this.onViewClick, this);
9372 this.store.on('beforeload', this.onBeforeLoad, this);
9373 this.store.on('load', this.onLoad, this);
9374 this.store.on('loadexception', this.onLoadException, this);
9377 this.resizer = new Roo.Resizable(this.list, {
9378 pinned:true, handles:'se'
9380 this.resizer.on('resize', function(r, w, h){
9381 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
9383 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
9384 this.restrictHeight();
9386 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
9390 this.editable = true;
9391 this.setEditable(false);
9396 if (typeof(this.events.add.listeners) != 'undefined') {
9398 this.addicon = this.wrap.createChild(
9399 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
9401 this.addicon.on('click', function(e) {
9402 this.fireEvent('add', this);
9405 if (typeof(this.events.edit.listeners) != 'undefined') {
9407 this.editicon = this.wrap.createChild(
9408 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
9410 this.editicon.setStyle('margin-left', '40px');
9412 this.editicon.on('click', function(e) {
9414 // we fire even if inothing is selected..
9415 this.fireEvent('edit', this, this.lastData );
9421 this.keyNav = new Roo.KeyNav(this.inputEl(), {
9423 this.inKeyMode = true;
9427 "down" : function(e){
9428 if(!this.isExpanded()){
9429 this.onTriggerClick();
9431 this.inKeyMode = true;
9436 "enter" : function(e){
9441 "esc" : function(e){
9445 "tab" : function(e){
9448 if(this.fireEvent("specialkey", this, e)){
9449 this.onViewClick(false);
9457 doRelay : function(foo, bar, hname){
9458 if(hname == 'down' || this.scope.isExpanded()){
9459 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
9468 this.queryDelay = Math.max(this.queryDelay || 10,
9469 this.mode == 'local' ? 10 : 250);
9472 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
9475 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
9477 if(this.editable !== false){
9478 this.inputEl().on("keyup", this.onKeyUp, this);
9480 if(this.forceSelection){
9481 this.on('blur', this.doForce, this);
9485 this.choices = this.el.select('ul.select2-choices', true).first();
9486 this.searchField = this.el.select('ul li.select2-search-field', true).first();
9490 onDestroy : function(){
9492 this.view.setStore(null);
9493 this.view.el.removeAllListeners();
9494 this.view.el.remove();
9495 this.view.purgeListeners();
9498 this.list.dom.innerHTML = '';
9501 this.store.un('beforeload', this.onBeforeLoad, this);
9502 this.store.un('load', this.onLoad, this);
9503 this.store.un('loadexception', this.onLoadException, this);
9505 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
9509 fireKey : function(e){
9510 if(e.isNavKeyPress() && !this.list.isVisible()){
9511 this.fireEvent("specialkey", this, e);
9516 onResize: function(w, h){
9517 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
9519 // if(typeof w != 'number'){
9520 // // we do not handle it!?!?
9523 // var tw = this.trigger.getWidth();
9524 // // tw += this.addicon ? this.addicon.getWidth() : 0;
9525 // // tw += this.editicon ? this.editicon.getWidth() : 0;
9527 // this.inputEl().setWidth( this.adjustWidth('input', x));
9529 // //this.trigger.setStyle('left', x+'px');
9531 // if(this.list && this.listWidth === undefined){
9532 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
9533 // this.list.setWidth(lw);
9534 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
9542 * Allow or prevent the user from directly editing the field text. If false is passed,
9543 * the user will only be able to select from the items defined in the dropdown list. This method
9544 * is the runtime equivalent of setting the 'editable' config option at config time.
9545 * @param {Boolean} value True to allow the user to directly edit the field text
9547 setEditable : function(value){
9548 if(value == this.editable){
9551 this.editable = value;
9553 this.inputEl().dom.setAttribute('readOnly', true);
9554 this.inputEl().on('mousedown', this.onTriggerClick, this);
9555 this.inputEl().addClass('x-combo-noedit');
9557 this.inputEl().dom.setAttribute('readOnly', false);
9558 this.inputEl().un('mousedown', this.onTriggerClick, this);
9559 this.inputEl().removeClass('x-combo-noedit');
9565 onBeforeLoad : function(combo,opts){
9570 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
9572 this.restrictHeight();
9573 this.selectedIndex = -1;
9577 onLoad : function(){
9579 this.hasQuery = false;
9585 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
9586 this.loading.hide();
9589 if(this.store.getCount() > 0){
9591 this.restrictHeight();
9592 if(this.lastQuery == this.allQuery){
9594 this.inputEl().dom.select();
9596 if(!this.selectByValue(this.value, true)){
9597 this.select(0, true);
9601 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
9602 this.taTask.delay(this.typeAheadDelay);
9606 this.onEmptyResults();
9612 onLoadException : function()
9614 this.hasQuery = false;
9616 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
9617 this.loading.hide();
9621 Roo.log(this.store.reader.jsonData);
9622 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
9624 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
9630 onTypeAhead : function(){
9631 if(this.store.getCount() > 0){
9632 var r = this.store.getAt(0);
9633 var newValue = r.data[this.displayField];
9634 var len = newValue.length;
9635 var selStart = this.getRawValue().length;
9637 if(selStart != len){
9638 this.setRawValue(newValue);
9639 this.selectText(selStart, newValue.length);
9645 onSelect : function(record, index){
9647 if(this.fireEvent('beforeselect', this, record, index) !== false){
9649 this.setFromData(index > -1 ? record.data : false);
9652 this.fireEvent('select', this, record, index);
9657 * Returns the currently selected field value or empty string if no value is set.
9658 * @return {String} value The selected value
9660 getValue : function(){
9663 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
9666 if(this.valueField){
9667 return typeof this.value != 'undefined' ? this.value : '';
9669 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
9674 * Clears any text/value currently set in the field
9676 clearValue : function(){
9677 if(this.hiddenField){
9678 this.hiddenField.dom.value = '';
9681 this.setRawValue('');
9682 this.lastSelectionText = '';
9687 * Sets the specified value into the field. If the value finds a match, the corresponding record text
9688 * will be displayed in the field. If the value does not match the data value of an existing item,
9689 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
9690 * Otherwise the field will be blank (although the value will still be set).
9691 * @param {String} value The value to match
9693 setValue : function(v){
9700 if(this.valueField){
9701 var r = this.findRecord(this.valueField, v);
9703 text = r.data[this.displayField];
9704 }else if(this.valueNotFoundText !== undefined){
9705 text = this.valueNotFoundText;
9708 this.lastSelectionText = text;
9709 if(this.hiddenField){
9710 this.hiddenField.dom.value = v;
9712 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
9716 * @property {Object} the last set data for the element
9721 * Sets the value of the field based on a object which is related to the record format for the store.
9722 * @param {Object} value the value to set as. or false on reset?
9724 setFromData : function(o){
9731 var dv = ''; // display value
9732 var vv = ''; // value value..
9734 if (this.displayField) {
9735 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
9737 // this is an error condition!!!
9738 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
9741 if(this.valueField){
9742 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
9745 if(this.hiddenField){
9746 this.hiddenField.dom.value = vv;
9748 this.lastSelectionText = dv;
9749 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
9753 // no hidden field.. - we store the value in 'value', but still display
9754 // display field!!!!
9755 this.lastSelectionText = dv;
9756 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
9763 // overridden so that last data is reset..
9764 this.setValue(this.originalValue);
9765 this.clearInvalid();
9766 this.lastData = false;
9768 this.view.clearSelections();
9772 findRecord : function(prop, value){
9774 if(this.store.getCount() > 0){
9775 this.store.each(function(r){
9776 if(r.data[prop] == value){
9788 // returns hidden if it's set..
9789 if (!this.rendered) {return ''};
9790 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
9794 onViewMove : function(e, t){
9795 this.inKeyMode = false;
9799 onViewOver : function(e, t){
9800 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
9803 var item = this.view.findItemFromChild(t);
9805 var index = this.view.indexOf(item);
9806 this.select(index, false);
9811 onViewClick : function(doFocus)
9813 var index = this.view.getSelectedIndexes()[0];
9814 var r = this.store.getAt(index);
9816 this.onSelect(r, index);
9818 if(doFocus !== false && !this.blockFocus){
9819 this.inputEl().focus();
9824 restrictHeight : function(){
9825 //this.innerList.dom.style.height = '';
9826 //var inner = this.innerList.dom;
9827 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
9828 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
9829 //this.list.beginUpdate();
9830 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
9831 this.list.alignTo(this.inputEl(), this.listAlign);
9832 //this.list.endUpdate();
9836 onEmptyResults : function(){
9841 * Returns true if the dropdown list is expanded, else false.
9843 isExpanded : function(){
9844 return this.list.isVisible();
9848 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
9849 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
9850 * @param {String} value The data value of the item to select
9851 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
9852 * selected item if it is not currently in view (defaults to true)
9853 * @return {Boolean} True if the value matched an item in the list, else false
9855 selectByValue : function(v, scrollIntoView){
9856 if(v !== undefined && v !== null){
9857 var r = this.findRecord(this.valueField || this.displayField, v);
9859 this.select(this.store.indexOf(r), scrollIntoView);
9867 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
9868 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
9869 * @param {Number} index The zero-based index of the list item to select
9870 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
9871 * selected item if it is not currently in view (defaults to true)
9873 select : function(index, scrollIntoView){
9874 this.selectedIndex = index;
9875 this.view.select(index);
9876 if(scrollIntoView !== false){
9877 var el = this.view.getNode(index);
9879 //this.innerList.scrollChildIntoView(el, false);
9886 selectNext : function(){
9887 var ct = this.store.getCount();
9889 if(this.selectedIndex == -1){
9891 }else if(this.selectedIndex < ct-1){
9892 this.select(this.selectedIndex+1);
9898 selectPrev : function(){
9899 var ct = this.store.getCount();
9901 if(this.selectedIndex == -1){
9903 }else if(this.selectedIndex != 0){
9904 this.select(this.selectedIndex-1);
9910 onKeyUp : function(e){
9911 if(this.editable !== false && !e.isSpecialKey()){
9912 this.lastKey = e.getKey();
9913 this.dqTask.delay(this.queryDelay);
9918 validateBlur : function(){
9919 return !this.list || !this.list.isVisible();
9923 initQuery : function(){
9924 this.doQuery(this.getRawValue());
9928 doForce : function(){
9929 if(this.el.dom.value.length > 0){
9931 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
9937 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
9938 * query allowing the query action to be canceled if needed.
9939 * @param {String} query The SQL query to execute
9940 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
9941 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
9942 * saved in the current store (defaults to false)
9944 doQuery : function(q, forceAll){
9946 if(q === undefined || q === null){
9955 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
9960 forceAll = qe.forceAll;
9961 if(forceAll === true || (q.length >= this.minChars)){
9963 this.hasQuery = true;
9965 if(this.lastQuery != q || this.alwaysQuery){
9967 if(this.mode == 'local'){
9968 this.selectedIndex = -1;
9970 this.store.clearFilter();
9972 this.store.filter(this.displayField, q);
9976 this.store.baseParams[this.queryParam] = q;
9978 var options = {params : this.getParams(q)};
9982 options.params.start = this.page * this.pageSize;
9985 this.store.load(options);
9989 this.selectedIndex = -1;
9994 this.loadNext = false;
9998 getParams : function(q){
10000 //p[this.queryParam] = q;
10004 p.limit = this.pageSize;
10010 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
10012 collapse : function(){
10013 if(!this.isExpanded()){
10018 Roo.get(document).un('mousedown', this.collapseIf, this);
10019 Roo.get(document).un('mousewheel', this.collapseIf, this);
10020 if (!this.editable) {
10021 Roo.get(document).un('keydown', this.listKeyPress, this);
10023 this.fireEvent('collapse', this);
10027 collapseIf : function(e){
10028 var in_combo = e.within(this.el);
10029 var in_list = e.within(this.list);
10031 if (in_combo || in_list) {
10032 //e.stopPropagation();
10041 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
10043 expand : function(){
10045 if(this.isExpanded() || !this.hasFocus){
10049 this.list.alignTo(this.inputEl(), this.listAlign);
10051 Roo.get(document).on('mousedown', this.collapseIf, this);
10052 Roo.get(document).on('mousewheel', this.collapseIf, this);
10053 if (!this.editable) {
10054 Roo.get(document).on('keydown', this.listKeyPress, this);
10057 this.fireEvent('expand', this);
10061 // Implements the default empty TriggerField.onTriggerClick function
10062 onTriggerClick : function()
10064 Roo.log('trigger click');
10071 this.loadNext = false;
10073 if(this.isExpanded()){
10075 if (!this.blockFocus) {
10076 this.inputEl().focus();
10080 this.hasFocus = true;
10081 if(this.triggerAction == 'all') {
10082 this.doQuery(this.allQuery, true);
10084 this.doQuery(this.getRawValue());
10086 if (!this.blockFocus) {
10087 this.inputEl().focus();
10091 listKeyPress : function(e)
10093 //Roo.log('listkeypress');
10094 // scroll to first matching element based on key pres..
10095 if (e.isSpecialKey()) {
10098 var k = String.fromCharCode(e.getKey()).toUpperCase();
10101 var csel = this.view.getSelectedNodes();
10102 var cselitem = false;
10104 var ix = this.view.indexOf(csel[0]);
10105 cselitem = this.store.getAt(ix);
10106 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
10112 this.store.each(function(v) {
10114 // start at existing selection.
10115 if (cselitem.id == v.id) {
10121 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
10122 match = this.store.indexOf(v);
10128 if (match === false) {
10129 return true; // no more action?
10132 this.view.select(match);
10133 var sn = Roo.get(this.view.getSelectedNodes()[0])
10134 //sn.scrollIntoView(sn.dom.parentNode, false);
10137 onViewScroll : function(e, t){
10139 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
10143 this.hasQuery = true;
10145 this.loading = this.list.select('.loading', true).first();
10147 if(this.loading === null){
10148 this.list.createChild({
10150 cls: 'loading select2-more-results select2-active',
10151 html: 'Loading more results...'
10154 this.loading = this.list.select('.loading', true).first();
10156 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
10158 this.loading.hide();
10161 this.loading.show();
10166 this.loadNext = true;
10168 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
10173 addItem : function(o)
10175 var dv = ''; // display value
10177 if (this.displayField) {
10178 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
10180 // this is an error condition!!!
10181 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
10188 var choice = this.choices.createChild({
10190 cls: 'select2-search-choice',
10199 cls: 'select2-search-choice-close',
10204 }, this.searchField);
10206 var close = choice.select('a.select2-search-choice-close', true).first()
10208 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
10215 this.inputEl().dom.value = '';
10219 onRemoveItem : function(e, _self, o)
10221 Roo.log('remove item');
10222 var index = this.item.indexOf(o.data) * 1;
10225 Roo.log('not this item?!');
10229 this.item.splice(index, 1);
10234 this.fireEvent('remove', this, e);
10238 syncValue : function()
10240 if(!this.item.length){
10247 Roo.each(this.item, function(i){
10248 if(_this.valueField){
10249 value.push(i[_this.valueField]);
10256 this.value = value.join(',');
10258 if(this.hiddenField){
10259 this.hiddenField.dom.value = this.value;
10263 clearItem : function()
10265 if(!this.multiple){
10271 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
10281 * @cfg {Boolean} grow
10285 * @cfg {Number} growMin
10289 * @cfg {Number} growMax
10299 * Ext JS Library 1.1.1
10300 * Copyright(c) 2006-2007, Ext JS, LLC.
10302 * Originally Released Under LGPL - original licence link has changed is not relivant.
10305 * <script type="text/javascript">
10310 * @extends Roo.util.Observable
10311 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
10312 * This class also supports single and multi selection modes. <br>
10313 * Create a data model bound view:
10315 var store = new Roo.data.Store(...);
10317 var view = new Roo.View({
10319 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
10321 singleSelect: true,
10322 selectedClass: "ydataview-selected",
10326 // listen for node click?
10327 view.on("click", function(vw, index, node, e){
10328 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
10332 dataModel.load("foobar.xml");
10334 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
10336 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
10337 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
10339 * Note: old style constructor is still suported (container, template, config)
10342 * Create a new View
10343 * @param {Object} config The config object
10346 Roo.View = function(config, depreciated_tpl, depreciated_config){
10348 if (typeof(depreciated_tpl) == 'undefined') {
10349 // new way.. - universal constructor.
10350 Roo.apply(this, config);
10351 this.el = Roo.get(this.el);
10354 this.el = Roo.get(config);
10355 this.tpl = depreciated_tpl;
10356 Roo.apply(this, depreciated_config);
10358 this.wrapEl = this.el.wrap().wrap();
10359 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
10362 if(typeof(this.tpl) == "string"){
10363 this.tpl = new Roo.Template(this.tpl);
10365 // support xtype ctors..
10366 this.tpl = new Roo.factory(this.tpl, Roo);
10370 this.tpl.compile();
10378 * @event beforeclick
10379 * Fires before a click is processed. Returns false to cancel the default action.
10380 * @param {Roo.View} this
10381 * @param {Number} index The index of the target node
10382 * @param {HTMLElement} node The target node
10383 * @param {Roo.EventObject} e The raw event object
10385 "beforeclick" : true,
10388 * Fires when a template node is clicked.
10389 * @param {Roo.View} this
10390 * @param {Number} index The index of the target node
10391 * @param {HTMLElement} node The target node
10392 * @param {Roo.EventObject} e The raw event object
10397 * Fires when a template node is double clicked.
10398 * @param {Roo.View} this
10399 * @param {Number} index The index of the target node
10400 * @param {HTMLElement} node The target node
10401 * @param {Roo.EventObject} e The raw event object
10405 * @event contextmenu
10406 * Fires when a template node is right clicked.
10407 * @param {Roo.View} this
10408 * @param {Number} index The index of the target node
10409 * @param {HTMLElement} node The target node
10410 * @param {Roo.EventObject} e The raw event object
10412 "contextmenu" : true,
10414 * @event selectionchange
10415 * Fires when the selected nodes change.
10416 * @param {Roo.View} this
10417 * @param {Array} selections Array of the selected nodes
10419 "selectionchange" : true,
10422 * @event beforeselect
10423 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
10424 * @param {Roo.View} this
10425 * @param {HTMLElement} node The node to be selected
10426 * @param {Array} selections Array of currently selected nodes
10428 "beforeselect" : true,
10430 * @event preparedata
10431 * Fires on every row to render, to allow you to change the data.
10432 * @param {Roo.View} this
10433 * @param {Object} data to be rendered (change this)
10435 "preparedata" : true
10443 "click": this.onClick,
10444 "dblclick": this.onDblClick,
10445 "contextmenu": this.onContextMenu,
10449 this.selections = [];
10451 this.cmp = new Roo.CompositeElementLite([]);
10453 this.store = Roo.factory(this.store, Roo.data);
10454 this.setStore(this.store, true);
10457 if ( this.footer && this.footer.xtype) {
10459 var fctr = this.wrapEl.appendChild(document.createElement("div"));
10461 this.footer.dataSource = this.store
10462 this.footer.container = fctr;
10463 this.footer = Roo.factory(this.footer, Roo);
10464 fctr.insertFirst(this.el);
10466 // this is a bit insane - as the paging toolbar seems to detach the el..
10467 // dom.parentNode.parentNode.parentNode
10468 // they get detached?
10472 Roo.View.superclass.constructor.call(this);
10477 Roo.extend(Roo.View, Roo.util.Observable, {
10480 * @cfg {Roo.data.Store} store Data store to load data from.
10485 * @cfg {String|Roo.Element} el The container element.
10490 * @cfg {String|Roo.Template} tpl The template used by this View
10494 * @cfg {String} dataName the named area of the template to use as the data area
10495 * Works with domtemplates roo-name="name"
10499 * @cfg {String} selectedClass The css class to add to selected nodes
10501 selectedClass : "x-view-selected",
10503 * @cfg {String} emptyText The empty text to show when nothing is loaded.
10508 * @cfg {String} text to display on mask (default Loading)
10512 * @cfg {Boolean} multiSelect Allow multiple selection
10514 multiSelect : false,
10516 * @cfg {Boolean} singleSelect Allow single selection
10518 singleSelect: false,
10521 * @cfg {Boolean} toggleSelect - selecting
10523 toggleSelect : false,
10526 * Returns the element this view is bound to.
10527 * @return {Roo.Element}
10529 getEl : function(){
10530 return this.wrapEl;
10536 * Refreshes the view. - called by datachanged on the store. - do not call directly.
10538 refresh : function(){
10539 Roo.log('refresh');
10542 // if we are using something like 'domtemplate', then
10543 // the what gets used is:
10544 // t.applySubtemplate(NAME, data, wrapping data..)
10545 // the outer template then get' applied with
10546 // the store 'extra data'
10547 // and the body get's added to the
10548 // roo-name="data" node?
10549 // <span class='roo-tpl-{name}'></span> ?????
10553 this.clearSelections();
10554 this.el.update("");
10556 var records = this.store.getRange();
10557 if(records.length < 1) {
10559 // is this valid?? = should it render a template??
10561 this.el.update(this.emptyText);
10565 if (this.dataName) {
10566 this.el.update(t.apply(this.store.meta)); //????
10567 el = this.el.child('.roo-tpl-' + this.dataName);
10570 for(var i = 0, len = records.length; i < len; i++){
10571 var data = this.prepareData(records[i].data, i, records[i]);
10572 this.fireEvent("preparedata", this, data, i, records[i]);
10573 html[html.length] = Roo.util.Format.trim(
10575 t.applySubtemplate(this.dataName, data, this.store.meta) :
10582 el.update(html.join(""));
10583 this.nodes = el.dom.childNodes;
10584 this.updateIndexes(0);
10589 * Function to override to reformat the data that is sent to
10590 * the template for each node.
10591 * DEPRICATED - use the preparedata event handler.
10592 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
10593 * a JSON object for an UpdateManager bound view).
10595 prepareData : function(data, index, record)
10597 this.fireEvent("preparedata", this, data, index, record);
10601 onUpdate : function(ds, record){
10602 Roo.log('on update');
10603 this.clearSelections();
10604 var index = this.store.indexOf(record);
10605 var n = this.nodes[index];
10606 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
10607 n.parentNode.removeChild(n);
10608 this.updateIndexes(index, index);
10614 onAdd : function(ds, records, index)
10616 Roo.log(['on Add', ds, records, index] );
10617 this.clearSelections();
10618 if(this.nodes.length == 0){
10622 var n = this.nodes[index];
10623 for(var i = 0, len = records.length; i < len; i++){
10624 var d = this.prepareData(records[i].data, i, records[i]);
10626 this.tpl.insertBefore(n, d);
10629 this.tpl.append(this.el, d);
10632 this.updateIndexes(index);
10635 onRemove : function(ds, record, index){
10636 Roo.log('onRemove');
10637 this.clearSelections();
10638 var el = this.dataName ?
10639 this.el.child('.roo-tpl-' + this.dataName) :
10642 el.dom.removeChild(this.nodes[index]);
10643 this.updateIndexes(index);
10647 * Refresh an individual node.
10648 * @param {Number} index
10650 refreshNode : function(index){
10651 this.onUpdate(this.store, this.store.getAt(index));
10654 updateIndexes : function(startIndex, endIndex){
10655 var ns = this.nodes;
10656 startIndex = startIndex || 0;
10657 endIndex = endIndex || ns.length - 1;
10658 for(var i = startIndex; i <= endIndex; i++){
10659 ns[i].nodeIndex = i;
10664 * Changes the data store this view uses and refresh the view.
10665 * @param {Store} store
10667 setStore : function(store, initial){
10668 if(!initial && this.store){
10669 this.store.un("datachanged", this.refresh);
10670 this.store.un("add", this.onAdd);
10671 this.store.un("remove", this.onRemove);
10672 this.store.un("update", this.onUpdate);
10673 this.store.un("clear", this.refresh);
10674 this.store.un("beforeload", this.onBeforeLoad);
10675 this.store.un("load", this.onLoad);
10676 this.store.un("loadexception", this.onLoad);
10680 store.on("datachanged", this.refresh, this);
10681 store.on("add", this.onAdd, this);
10682 store.on("remove", this.onRemove, this);
10683 store.on("update", this.onUpdate, this);
10684 store.on("clear", this.refresh, this);
10685 store.on("beforeload", this.onBeforeLoad, this);
10686 store.on("load", this.onLoad, this);
10687 store.on("loadexception", this.onLoad, this);
10695 * onbeforeLoad - masks the loading area.
10698 onBeforeLoad : function(store,opts)
10700 Roo.log('onBeforeLoad');
10702 this.el.update("");
10704 this.el.mask(this.mask ? this.mask : "Loading" );
10706 onLoad : function ()
10713 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
10714 * @param {HTMLElement} node
10715 * @return {HTMLElement} The template node
10717 findItemFromChild : function(node){
10718 var el = this.dataName ?
10719 this.el.child('.roo-tpl-' + this.dataName,true) :
10722 if(!node || node.parentNode == el){
10725 var p = node.parentNode;
10726 while(p && p != el){
10727 if(p.parentNode == el){
10736 onClick : function(e){
10737 var item = this.findItemFromChild(e.getTarget());
10739 var index = this.indexOf(item);
10740 if(this.onItemClick(item, index, e) !== false){
10741 this.fireEvent("click", this, index, item, e);
10744 this.clearSelections();
10749 onContextMenu : function(e){
10750 var item = this.findItemFromChild(e.getTarget());
10752 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
10757 onDblClick : function(e){
10758 var item = this.findItemFromChild(e.getTarget());
10760 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
10764 onItemClick : function(item, index, e)
10766 if(this.fireEvent("beforeclick", this, index, item, e) === false){
10769 if (this.toggleSelect) {
10770 var m = this.isSelected(item) ? 'unselect' : 'select';
10773 _t[m](item, true, false);
10776 if(this.multiSelect || this.singleSelect){
10777 if(this.multiSelect && e.shiftKey && this.lastSelection){
10778 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
10780 this.select(item, this.multiSelect && e.ctrlKey);
10781 this.lastSelection = item;
10783 e.preventDefault();
10789 * Get the number of selected nodes.
10792 getSelectionCount : function(){
10793 return this.selections.length;
10797 * Get the currently selected nodes.
10798 * @return {Array} An array of HTMLElements
10800 getSelectedNodes : function(){
10801 return this.selections;
10805 * Get the indexes of the selected nodes.
10808 getSelectedIndexes : function(){
10809 var indexes = [], s = this.selections;
10810 for(var i = 0, len = s.length; i < len; i++){
10811 indexes.push(s[i].nodeIndex);
10817 * Clear all selections
10818 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
10820 clearSelections : function(suppressEvent){
10821 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
10822 this.cmp.elements = this.selections;
10823 this.cmp.removeClass(this.selectedClass);
10824 this.selections = [];
10825 if(!suppressEvent){
10826 this.fireEvent("selectionchange", this, this.selections);
10832 * Returns true if the passed node is selected
10833 * @param {HTMLElement/Number} node The node or node index
10834 * @return {Boolean}
10836 isSelected : function(node){
10837 var s = this.selections;
10841 node = this.getNode(node);
10842 return s.indexOf(node) !== -1;
10847 * @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
10848 * @param {Boolean} keepExisting (optional) true to keep existing selections
10849 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
10851 select : function(nodeInfo, keepExisting, suppressEvent){
10852 if(nodeInfo instanceof Array){
10854 this.clearSelections(true);
10856 for(var i = 0, len = nodeInfo.length; i < len; i++){
10857 this.select(nodeInfo[i], true, true);
10861 var node = this.getNode(nodeInfo);
10862 if(!node || this.isSelected(node)){
10863 return; // already selected.
10866 this.clearSelections(true);
10868 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
10869 Roo.fly(node).addClass(this.selectedClass);
10870 this.selections.push(node);
10871 if(!suppressEvent){
10872 this.fireEvent("selectionchange", this, this.selections);
10880 * @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
10881 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
10882 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
10884 unselect : function(nodeInfo, keepExisting, suppressEvent)
10886 if(nodeInfo instanceof Array){
10887 Roo.each(this.selections, function(s) {
10888 this.unselect(s, nodeInfo);
10892 var node = this.getNode(nodeInfo);
10893 if(!node || !this.isSelected(node)){
10894 Roo.log("not selected");
10895 return; // not selected.
10899 Roo.each(this.selections, function(s) {
10901 Roo.fly(node).removeClass(this.selectedClass);
10908 this.selections= ns;
10909 this.fireEvent("selectionchange", this, this.selections);
10913 * Gets a template node.
10914 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
10915 * @return {HTMLElement} The node or null if it wasn't found
10917 getNode : function(nodeInfo){
10918 if(typeof nodeInfo == "string"){
10919 return document.getElementById(nodeInfo);
10920 }else if(typeof nodeInfo == "number"){
10921 return this.nodes[nodeInfo];
10927 * Gets a range template nodes.
10928 * @param {Number} startIndex
10929 * @param {Number} endIndex
10930 * @return {Array} An array of nodes
10932 getNodes : function(start, end){
10933 var ns = this.nodes;
10934 start = start || 0;
10935 end = typeof end == "undefined" ? ns.length - 1 : end;
10938 for(var i = start; i <= end; i++){
10942 for(var i = start; i >= end; i--){
10950 * Finds the index of the passed node
10951 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
10952 * @return {Number} The index of the node or -1
10954 indexOf : function(node){
10955 node = this.getNode(node);
10956 if(typeof node.nodeIndex == "number"){
10957 return node.nodeIndex;
10959 var ns = this.nodes;
10960 for(var i = 0, len = ns.length; i < len; i++){
10971 * based on jquery fullcalendar
10975 Roo.bootstrap = Roo.bootstrap || {};
10977 * @class Roo.bootstrap.Calendar
10978 * @extends Roo.bootstrap.Component
10979 * Bootstrap Calendar class
10980 * @cfg {Boolean} loadMask (true|false) default false
10981 * @cfg {Object} header generate the user specific header of the calendar, default false
10984 * Create a new Container
10985 * @param {Object} config The config object
10990 Roo.bootstrap.Calendar = function(config){
10991 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
10995 * Fires when a date is selected
10996 * @param {DatePicker} this
10997 * @param {Date} date The selected date
11001 * @event monthchange
11002 * Fires when the displayed month changes
11003 * @param {DatePicker} this
11004 * @param {Date} date The selected month
11006 'monthchange': true,
11008 * @event evententer
11009 * Fires when mouse over an event
11010 * @param {Calendar} this
11011 * @param {event} Event
11013 'evententer': true,
11015 * @event eventleave
11016 * Fires when the mouse leaves an
11017 * @param {Calendar} this
11020 'eventleave': true,
11022 * @event eventclick
11023 * Fires when the mouse click an
11024 * @param {Calendar} this
11033 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
11036 * @cfg {Number} startDay
11037 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
11045 getAutoCreate : function(){
11048 var fc_button = function(name, corner, style, content ) {
11049 return Roo.apply({},{
11051 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
11053 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
11056 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
11067 style : 'width:100%',
11074 cls : 'fc-header-left',
11076 fc_button('prev', 'left', 'arrow', '‹' ),
11077 fc_button('next', 'right', 'arrow', '›' ),
11078 { tag: 'span', cls: 'fc-header-space' },
11079 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
11087 cls : 'fc-header-center',
11091 cls: 'fc-header-title',
11094 html : 'month / year'
11102 cls : 'fc-header-right',
11104 /* fc_button('month', 'left', '', 'month' ),
11105 fc_button('week', '', '', 'week' ),
11106 fc_button('day', 'right', '', 'day' )
11118 header = this.header;
11121 var cal_heads = function() {
11123 // fixme - handle this.
11125 for (var i =0; i < Date.dayNames.length; i++) {
11126 var d = Date.dayNames[i];
11129 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
11130 html : d.substring(0,3)
11134 ret[0].cls += ' fc-first';
11135 ret[6].cls += ' fc-last';
11138 var cal_cell = function(n) {
11141 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
11146 cls: 'fc-day-number',
11150 cls: 'fc-day-content',
11154 style: 'position: relative;' // height: 17px;
11166 var cal_rows = function() {
11169 for (var r = 0; r < 6; r++) {
11176 for (var i =0; i < Date.dayNames.length; i++) {
11177 var d = Date.dayNames[i];
11178 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
11181 row.cn[0].cls+=' fc-first';
11182 row.cn[0].cn[0].style = 'min-height:90px';
11183 row.cn[6].cls+=' fc-last';
11187 ret[0].cls += ' fc-first';
11188 ret[4].cls += ' fc-prev-last';
11189 ret[5].cls += ' fc-last';
11196 cls: 'fc-border-separate',
11197 style : 'width:100%',
11205 cls : 'fc-first fc-last',
11223 cls : 'fc-content',
11224 style : "position: relative;",
11227 cls : 'fc-view fc-view-month fc-grid',
11228 style : 'position: relative',
11229 unselectable : 'on',
11232 cls : 'fc-event-container',
11233 style : 'position:absolute;z-index:8;top:0;left:0;'
11251 initEvents : function()
11254 throw "can not find store for calendar";
11260 style: "text-align:center",
11264 style: "background-color:white;width:50%;margin:250 auto",
11268 src: rootURL + '/roojs1/images/ux/lightbox/loading.gif'
11279 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
11281 var size = this.el.select('.fc-content', true).first().getSize();
11282 this.maskEl.setSize(size.width, size.height);
11283 this.maskEl.enableDisplayMode("block");
11284 if(!this.loadMask){
11285 this.maskEl.hide();
11288 this.store = Roo.factory(this.store, Roo.data);
11289 this.store.on('load', this.onLoad, this);
11290 this.store.on('beforeload', this.onBeforeLoad, this);
11294 this.cells = this.el.select('.fc-day',true);
11295 //Roo.log(this.cells);
11296 this.textNodes = this.el.query('.fc-day-number');
11297 this.cells.addClassOnOver('fc-state-hover');
11299 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
11300 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
11301 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
11302 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
11304 this.on('monthchange', this.onMonthChange, this);
11306 this.update(new Date().clearTime());
11309 resize : function() {
11310 var sz = this.el.getSize();
11312 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
11313 this.el.select('.fc-day-content div',true).setHeight(34);
11318 showPrevMonth : function(e){
11319 this.update(this.activeDate.add("mo", -1));
11321 showToday : function(e){
11322 this.update(new Date().clearTime());
11325 showNextMonth : function(e){
11326 this.update(this.activeDate.add("mo", 1));
11330 showPrevYear : function(){
11331 this.update(this.activeDate.add("y", -1));
11335 showNextYear : function(){
11336 this.update(this.activeDate.add("y", 1));
11341 update : function(date)
11343 var vd = this.activeDate;
11344 this.activeDate = date;
11345 // if(vd && this.el){
11346 // var t = date.getTime();
11347 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
11348 // Roo.log('using add remove');
11350 // this.fireEvent('monthchange', this, date);
11352 // this.cells.removeClass("fc-state-highlight");
11353 // this.cells.each(function(c){
11354 // if(c.dateValue == t){
11355 // c.addClass("fc-state-highlight");
11356 // setTimeout(function(){
11357 // try{c.dom.firstChild.focus();}catch(e){}
11367 var days = date.getDaysInMonth();
11369 var firstOfMonth = date.getFirstDateOfMonth();
11370 var startingPos = firstOfMonth.getDay()-this.startDay;
11372 if(startingPos < this.startDay){
11376 var pm = date.add(Date.MONTH, -1);
11377 var prevStart = pm.getDaysInMonth()-startingPos;
11379 this.cells = this.el.select('.fc-day',true);
11380 this.textNodes = this.el.query('.fc-day-number');
11381 this.cells.addClassOnOver('fc-state-hover');
11383 var cells = this.cells.elements;
11384 var textEls = this.textNodes;
11386 Roo.each(cells, function(cell){
11387 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
11390 days += startingPos;
11392 // convert everything to numbers so it's fast
11393 var day = 86400000;
11394 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
11397 //Roo.log(prevStart);
11399 var today = new Date().clearTime().getTime();
11400 var sel = date.clearTime().getTime();
11401 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
11402 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
11403 var ddMatch = this.disabledDatesRE;
11404 var ddText = this.disabledDatesText;
11405 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
11406 var ddaysText = this.disabledDaysText;
11407 var format = this.format;
11409 var setCellClass = function(cal, cell){
11411 //Roo.log('set Cell Class');
11413 var t = d.getTime();
11417 cell.dateValue = t;
11419 cell.className += " fc-today";
11420 cell.className += " fc-state-highlight";
11421 cell.title = cal.todayText;
11424 // disable highlight in other month..
11425 //cell.className += " fc-state-highlight";
11430 cell.className = " fc-state-disabled";
11431 cell.title = cal.minText;
11435 cell.className = " fc-state-disabled";
11436 cell.title = cal.maxText;
11440 if(ddays.indexOf(d.getDay()) != -1){
11441 cell.title = ddaysText;
11442 cell.className = " fc-state-disabled";
11445 if(ddMatch && format){
11446 var fvalue = d.dateFormat(format);
11447 if(ddMatch.test(fvalue)){
11448 cell.title = ddText.replace("%0", fvalue);
11449 cell.className = " fc-state-disabled";
11453 if (!cell.initialClassName) {
11454 cell.initialClassName = cell.dom.className;
11457 cell.dom.className = cell.initialClassName + ' ' + cell.className;
11462 for(; i < startingPos; i++) {
11463 textEls[i].innerHTML = (++prevStart);
11464 d.setDate(d.getDate()+1);
11466 cells[i].className = "fc-past fc-other-month";
11467 setCellClass(this, cells[i]);
11472 for(; i < days; i++){
11473 intDay = i - startingPos + 1;
11474 textEls[i].innerHTML = (intDay);
11475 d.setDate(d.getDate()+1);
11477 cells[i].className = ''; // "x-date-active";
11478 setCellClass(this, cells[i]);
11482 for(; i < 42; i++) {
11483 textEls[i].innerHTML = (++extraDays);
11484 d.setDate(d.getDate()+1);
11486 cells[i].className = "fc-future fc-other-month";
11487 setCellClass(this, cells[i]);
11490 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
11492 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
11494 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
11495 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
11497 if(totalRows != 6){
11498 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
11499 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
11502 this.fireEvent('monthchange', this, date);
11506 if(!this.internalRender){
11507 var main = this.el.dom.firstChild;
11508 var w = main.offsetWidth;
11509 this.el.setWidth(w + this.el.getBorderWidth("lr"));
11510 Roo.fly(main).setWidth(w);
11511 this.internalRender = true;
11512 // opera does not respect the auto grow header center column
11513 // then, after it gets a width opera refuses to recalculate
11514 // without a second pass
11515 if(Roo.isOpera && !this.secondPass){
11516 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
11517 this.secondPass = true;
11518 this.update.defer(10, this, [date]);
11525 findCell : function(dt) {
11526 dt = dt.clearTime().getTime();
11528 this.cells.each(function(c){
11529 //Roo.log("check " +c.dateValue + '?=' + dt);
11530 if(c.dateValue == dt){
11540 findCells : function(ev) {
11541 var s = ev.start.clone().clearTime().getTime();
11543 var e= ev.end.clone().clearTime().getTime();
11546 this.cells.each(function(c){
11547 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
11549 if(c.dateValue > e){
11552 if(c.dateValue < s){
11561 findBestRow: function(cells)
11565 for (var i =0 ; i < cells.length;i++) {
11566 ret = Math.max(cells[i].rows || 0,ret);
11573 addItem : function(ev)
11575 // look for vertical location slot in
11576 var cells = this.findCells(ev);
11578 ev.row = this.findBestRow(cells);
11580 // work out the location.
11584 for(var i =0; i < cells.length; i++) {
11592 if (crow.start.getY() == cells[i].getY()) {
11594 crow.end = cells[i];
11611 for (var i = 0; i < cells.length;i++) {
11612 cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
11616 this.calevents.push(ev);
11619 clearEvents: function() {
11621 if(!this.calevents){
11625 Roo.each(this.cells.elements, function(c){
11629 Roo.each(this.calevents, function(e) {
11630 Roo.each(e.els, function(el) {
11631 el.un('mouseenter' ,this.onEventEnter, this);
11632 el.un('mouseleave' ,this.onEventLeave, this);
11639 renderEvents: function()
11641 // first make sure there is enough space..
11642 this.cells.each(function(c) {
11644 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, Math.min(5, c.rows) * 20));
11647 for (var e = 0; e < this.calevents.length; e++) {
11649 var ev = this.calevents[e];
11650 var cells = ev.cells;
11651 var rows = ev.rows;
11653 for(var i =0; i < rows.length; i++) {
11656 // how many rows should it span..
11659 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
11660 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
11662 unselectable : "on",
11665 cls: 'fc-event-inner',
11669 // cls: 'fc-event-time',
11670 // html : cells.length > 1 ? '' : ev.time
11674 cls: 'fc-event-title',
11675 html : String.format('{0}', ev.title)
11682 cls: 'ui-resizable-handle ui-resizable-e',
11683 html : '  '
11689 var more = this.cells.item(this.cells.indexOf(cells[0])).more;
11692 Roo.log(this.cells.item(this.cells.indexOf(cells[0])));
11693 this.cells.item(this.cells.indexOf(cells[0])).more.push(ev);
11698 Roo.log(this.cells.item(this.cells.indexOf(cells[0])));
11699 cfg.cn[0].cn[0].html = 'More';
11700 this.cells.item(this.cells.indexOf(cells[0])).more.push(ev);
11704 cfg.cls += ' fc-event-start';
11706 if ((i+1) == rows.length) {
11707 cfg.cls += ' fc-event-end';
11710 var ctr = this.el.select('.fc-event-container',true).first();
11711 var cg = ctr.createChild(cfg);
11713 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
11714 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
11716 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
11717 cg.setWidth(ebox.right - sbox.x -2);
11720 cg.on('click', this.onMoreEventClick, this, ev);
11724 cg.on('mouseenter' ,this.onEventEnter, this, ev);
11725 cg.on('mouseleave' ,this.onEventLeave, this, ev);
11726 cg.on('click', this.onEventClick, this, ev);
11738 onEventEnter: function (e, el,event,d) {
11739 this.fireEvent('evententer', this, el, event);
11742 onEventLeave: function (e, el,event,d) {
11743 this.fireEvent('eventleave', this, el, event);
11746 onEventClick: function (e, el,event,d) {
11747 this.fireEvent('eventclick', this, el, event);
11750 onMonthChange: function () {
11754 onMoreEventClick: function(e, el, event)
11758 Roo.log(this.calpopover);
11763 var more = this.cells.item(this.cells.indexOf(event.cells[0])).more;
11765 this.calpopover.placement = 'right';
11766 this.calpopover.setTitle('More');
11768 this.calpopover.setContent('');
11770 var ctr = this.calpopover.el.select('.popover-content', true).first();
11772 Roo.each(more, function(m){
11774 cls : 'fc-event-hori fc-event-draggable',
11777 var cg = ctr.createChild(cfg);
11779 cg.on('click', _this.onEventClick, _this, m);
11782 this.calpopover.show(el);
11787 onLoad: function ()
11789 this.calevents = [];
11792 if(this.store.getCount() > 0){
11793 this.store.data.each(function(d){
11796 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
11797 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
11798 time : d.data.start_time,
11799 title : d.data.title,
11800 description : d.data.description,
11801 venue : d.data.venue
11805 Roo.log('calevents!!!!!!!!!!!!!!!!!!!!!!');
11806 Roo.log(this.calevents);
11808 this.renderEvents();
11810 Roo.log(this.cells);
11813 this.maskEl.hide();
11817 onBeforeLoad: function()
11819 this.clearEvents();
11822 this.maskEl.show();
11836 * @class Roo.bootstrap.Popover
11837 * @extends Roo.bootstrap.Component
11838 * Bootstrap Popover class
11839 * @cfg {String} html contents of the popover (or false to use children..)
11840 * @cfg {String} title of popover (or false to hide)
11841 * @cfg {String} placement how it is placed
11842 * @cfg {String} trigger click || hover (or false to trigger manually)
11843 * @cfg {String} over what (parent or false to trigger manually.)
11846 * Create a new Popover
11847 * @param {Object} config The config object
11850 Roo.bootstrap.Popover = function(config){
11851 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
11854 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
11856 title: 'Fill in a title',
11859 placement : 'right',
11860 trigger : 'hover', // hover
11864 can_build_overlaid : false,
11866 getChildContainer : function()
11868 return this.el.select('.popover-content',true).first();
11871 getAutoCreate : function(){
11872 Roo.log('make popover?');
11874 cls : 'popover roo-dynamic',
11875 style: 'display:block',
11881 cls : 'popover-inner',
11885 cls: 'popover-title',
11889 cls : 'popover-content',
11900 setTitle: function(str)
11902 this.el.select('.popover-title',true).first().dom.innerHTML = str;
11904 setContent: function(str)
11906 this.el.select('.popover-content',true).first().dom.innerHTML = str;
11908 // as it get's added to the bottom of the page.
11909 onRender : function(ct, position)
11911 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
11913 var cfg = Roo.apply({}, this.getAutoCreate());
11917 cfg.cls += ' ' + this.cls;
11920 cfg.style = this.style;
11922 Roo.log("adding to ")
11923 this.el = Roo.get(document.body).createChild(cfg, position);
11929 initEvents : function()
11931 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
11932 this.el.enableDisplayMode('block');
11934 if (this.over === false) {
11937 if (this.triggers === false) {
11940 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
11941 var triggers = this.trigger ? this.trigger.split(' ') : [];
11942 Roo.each(triggers, function(trigger) {
11944 if (trigger == 'click') {
11945 on_el.on('click', this.toggle, this);
11946 } else if (trigger != 'manual') {
11947 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
11948 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
11950 on_el.on(eventIn ,this.enter, this);
11951 on_el.on(eventOut, this.leave, this);
11962 toggle : function () {
11963 this.hoverState == 'in' ? this.leave() : this.enter();
11966 enter : function () {
11969 clearTimeout(this.timeout);
11971 this.hoverState = 'in'
11973 if (!this.delay || !this.delay.show) {
11978 this.timeout = setTimeout(function () {
11979 if (_t.hoverState == 'in') {
11982 }, this.delay.show)
11984 leave : function() {
11985 clearTimeout(this.timeout);
11987 this.hoverState = 'out'
11989 if (!this.delay || !this.delay.hide) {
11994 this.timeout = setTimeout(function () {
11995 if (_t.hoverState == 'out') {
11998 }, this.delay.hide)
12001 show : function (on_el)
12004 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
12007 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
12008 if (this.html !== false) {
12009 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
12011 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
12012 if (!this.title.length) {
12013 this.el.select('.popover-title',true).hide();
12016 var placement = typeof this.placement == 'function' ?
12017 this.placement.call(this, this.el, on_el) :
12020 var autoToken = /\s?auto?\s?/i;
12021 var autoPlace = autoToken.test(placement);
12023 placement = placement.replace(autoToken, '') || 'top';
12027 //this.el.setXY([0,0]);
12029 this.el.dom.style.display='block';
12030 this.el.addClass(placement);
12032 //this.el.appendTo(on_el);
12034 var p = this.getPosition();
12035 var box = this.el.getBox();
12040 var align = Roo.bootstrap.Popover.alignment[placement]
12041 this.el.alignTo(on_el, align[0],align[1]);
12042 //var arrow = this.el.select('.arrow',true).first();
12043 //arrow.set(align[2],
12045 this.el.addClass('in');
12046 this.hoverState = null;
12048 if (this.el.hasClass('fade')) {
12055 this.el.setXY([0,0]);
12056 this.el.removeClass('in');
12063 Roo.bootstrap.Popover.alignment = {
12064 'left' : ['r-l', [-10,0], 'right'],
12065 'right' : ['l-r', [10,0], 'left'],
12066 'bottom' : ['t-b', [0,10], 'top'],
12067 'top' : [ 'b-t', [0,-10], 'bottom']
12078 * @class Roo.bootstrap.Progress
12079 * @extends Roo.bootstrap.Component
12080 * Bootstrap Progress class
12081 * @cfg {Boolean} striped striped of the progress bar
12082 * @cfg {Boolean} active animated of the progress bar
12086 * Create a new Progress
12087 * @param {Object} config The config object
12090 Roo.bootstrap.Progress = function(config){
12091 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
12094 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
12099 getAutoCreate : function(){
12107 cfg.cls += ' progress-striped';
12111 cfg.cls += ' active';
12130 * @class Roo.bootstrap.ProgressBar
12131 * @extends Roo.bootstrap.Component
12132 * Bootstrap ProgressBar class
12133 * @cfg {Number} aria_valuenow aria-value now
12134 * @cfg {Number} aria_valuemin aria-value min
12135 * @cfg {Number} aria_valuemax aria-value max
12136 * @cfg {String} label label for the progress bar
12137 * @cfg {String} panel (success | info | warning | danger )
12138 * @cfg {String} role role of the progress bar
12139 * @cfg {String} sr_only text
12143 * Create a new ProgressBar
12144 * @param {Object} config The config object
12147 Roo.bootstrap.ProgressBar = function(config){
12148 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
12151 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
12155 aria_valuemax : 100,
12161 getAutoCreate : function()
12166 cls: 'progress-bar',
12167 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
12179 cfg.role = this.role;
12182 if(this.aria_valuenow){
12183 cfg['aria-valuenow'] = this.aria_valuenow;
12186 if(this.aria_valuemin){
12187 cfg['aria-valuemin'] = this.aria_valuemin;
12190 if(this.aria_valuemax){
12191 cfg['aria-valuemax'] = this.aria_valuemax;
12194 if(this.label && !this.sr_only){
12195 cfg.html = this.label;
12199 cfg.cls += ' progress-bar-' + this.panel;
12205 update : function(aria_valuenow)
12207 this.aria_valuenow = aria_valuenow;
12209 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
12224 * @class Roo.bootstrap.TabPanel
12225 * @extends Roo.bootstrap.Component
12226 * Bootstrap TabPanel class
12227 * @cfg {Boolean} active panel active
12228 * @cfg {String} html panel content
12229 * @cfg {String} tabId tab relate id
12230 * @cfg {String} navId The navbar which triggers show hide
12234 * Create a new TabPanel
12235 * @param {Object} config The config object
12238 Roo.bootstrap.TabPanel = function(config){
12239 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
12243 * Fires when the active status changes
12244 * @param {Roo.bootstrap.TabPanel} this
12245 * @param {Boolean} state the new state
12252 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
12259 getAutoCreate : function(){
12263 html: this.html || ''
12267 cfg.cls += ' active';
12271 cfg.tabId = this.tabId;
12276 onRender : function(ct, position)
12278 // Roo.log("Call onRender: " + this.xtype);
12280 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
12282 if (this.navId && this.tabId) {
12283 var item = Roo.bootstrap.NavGroup.get(this.navId).getNavItem(this.tabId);
12285 Roo.log("could not find navID:" + this.navId + ", tabId: " + this.tabId);
12287 item.on('changed', function(item, state) {
12288 this.setActive(state);
12294 setActive: function(state)
12296 Roo.log("panel - set active " + this.tabId + "=" + state);
12298 this.active = state;
12300 this.el.removeClass('active');
12302 } else if (!this.el.hasClass('active')) {
12303 this.el.addClass('active');
12305 this.fireEvent('changed', this, state);
12322 * @class Roo.bootstrap.DateField
12323 * @extends Roo.bootstrap.Input
12324 * Bootstrap DateField class
12325 * @cfg {Number} weekStart default 0
12326 * @cfg {Number} weekStart default 0
12327 * @cfg {Number} viewMode default empty, (months|years)
12328 * @cfg {Number} minViewMode default empty, (months|years)
12329 * @cfg {Number} startDate default -Infinity
12330 * @cfg {Number} endDate default Infinity
12331 * @cfg {Boolean} todayHighlight default false
12332 * @cfg {Boolean} todayBtn default false
12333 * @cfg {Boolean} calendarWeeks default false
12334 * @cfg {Object} daysOfWeekDisabled default empty
12336 * @cfg {Boolean} keyboardNavigation default true
12337 * @cfg {String} language default en
12340 * Create a new DateField
12341 * @param {Object} config The config object
12344 Roo.bootstrap.DateField = function(config){
12345 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
12349 * Fires when this field show.
12350 * @param {Roo.bootstrap.DateField} this
12351 * @param {Mixed} date The date value
12356 * Fires when this field hide.
12357 * @param {Roo.bootstrap.DateField} this
12358 * @param {Mixed} date The date value
12363 * Fires when select a date.
12364 * @param {Roo.bootstrap.DateField} this
12365 * @param {Mixed} date The date value
12371 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
12374 * @cfg {String} format
12375 * The default date format string which can be overriden for localization support. The format must be
12376 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
12380 * @cfg {String} altFormats
12381 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
12382 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
12384 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
12392 todayHighlight : false,
12398 keyboardNavigation: true,
12400 calendarWeeks: false,
12402 startDate: -Infinity,
12406 daysOfWeekDisabled: [],
12410 UTCDate: function()
12412 return new Date(Date.UTC.apply(Date, arguments));
12415 UTCToday: function()
12417 var today = new Date();
12418 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
12421 getDate: function() {
12422 var d = this.getUTCDate();
12423 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
12426 getUTCDate: function() {
12430 setDate: function(d) {
12431 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
12434 setUTCDate: function(d) {
12436 this.setValue(this.formatDate(this.date));
12439 onRender: function(ct, position)
12442 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
12444 this.language = this.language || 'en';
12445 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
12446 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
12448 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
12449 this.format = this.format || 'm/d/y';
12450 this.isInline = false;
12451 this.isInput = true;
12452 this.component = this.el.select('.add-on', true).first() || false;
12453 this.component = (this.component && this.component.length === 0) ? false : this.component;
12454 this.hasInput = this.component && this.inputEL().length;
12456 if (typeof(this.minViewMode === 'string')) {
12457 switch (this.minViewMode) {
12459 this.minViewMode = 1;
12462 this.minViewMode = 2;
12465 this.minViewMode = 0;
12470 if (typeof(this.viewMode === 'string')) {
12471 switch (this.viewMode) {
12484 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
12486 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12488 this.picker().on('mousedown', this.onMousedown, this);
12489 this.picker().on('click', this.onClick, this);
12491 this.picker().addClass('datepicker-dropdown');
12493 this.startViewMode = this.viewMode;
12496 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
12497 if(!this.calendarWeeks){
12502 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
12503 v.attr('colspan', function(i, val){
12504 return parseInt(val) + 1;
12509 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
12511 this.setStartDate(this.startDate);
12512 this.setEndDate(this.endDate);
12514 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
12521 if(this.isInline) {
12526 picker : function()
12528 return this.el.select('.datepicker', true).first();
12531 fillDow: function()
12533 var dowCnt = this.weekStart;
12542 if(this.calendarWeeks){
12550 while (dowCnt < this.weekStart + 7) {
12554 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
12558 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
12561 fillMonths: function()
12564 var months = this.picker().select('>.datepicker-months td', true).first();
12566 months.dom.innerHTML = '';
12572 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
12575 months.createChild(month);
12580 update: function(){
12582 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
12584 if (this.date < this.startDate) {
12585 this.viewDate = new Date(this.startDate);
12586 } else if (this.date > this.endDate) {
12587 this.viewDate = new Date(this.endDate);
12589 this.viewDate = new Date(this.date);
12596 var d = new Date(this.viewDate),
12597 year = d.getUTCFullYear(),
12598 month = d.getUTCMonth(),
12599 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
12600 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
12601 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
12602 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
12603 currentDate = this.date && this.date.valueOf(),
12604 today = this.UTCToday();
12606 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
12608 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
12610 // this.picker.select('>tfoot th.today').
12611 // .text(dates[this.language].today)
12612 // .toggle(this.todayBtn !== false);
12614 this.updateNavArrows();
12617 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
12619 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
12621 prevMonth.setUTCDate(day);
12623 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
12625 var nextMonth = new Date(prevMonth);
12627 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
12629 nextMonth = nextMonth.valueOf();
12631 var fillMonths = false;
12633 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
12635 while(prevMonth.valueOf() < nextMonth) {
12638 if (prevMonth.getUTCDay() === this.weekStart) {
12640 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
12648 if(this.calendarWeeks){
12649 // ISO 8601: First week contains first thursday.
12650 // ISO also states week starts on Monday, but we can be more abstract here.
12652 // Start of current week: based on weekstart/current date
12653 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
12654 // Thursday of this week
12655 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
12656 // First Thursday of year, year from thursday
12657 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
12658 // Calendar week: ms between thursdays, div ms per day, div 7 days
12659 calWeek = (th - yth) / 864e5 / 7 + 1;
12661 fillMonths.cn.push({
12669 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
12671 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
12674 if (this.todayHighlight &&
12675 prevMonth.getUTCFullYear() == today.getFullYear() &&
12676 prevMonth.getUTCMonth() == today.getMonth() &&
12677 prevMonth.getUTCDate() == today.getDate()) {
12678 clsName += ' today';
12681 if (currentDate && prevMonth.valueOf() === currentDate) {
12682 clsName += ' active';
12685 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
12686 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
12687 clsName += ' disabled';
12690 fillMonths.cn.push({
12692 cls: 'day ' + clsName,
12693 html: prevMonth.getDate()
12696 prevMonth.setDate(prevMonth.getDate()+1);
12699 var currentYear = this.date && this.date.getUTCFullYear();
12700 var currentMonth = this.date && this.date.getUTCMonth();
12702 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
12704 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
12705 v.removeClass('active');
12707 if(currentYear === year && k === currentMonth){
12708 v.addClass('active');
12711 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
12712 v.addClass('disabled');
12718 year = parseInt(year/10, 10) * 10;
12720 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
12722 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
12725 for (var i = -1; i < 11; i++) {
12726 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
12728 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
12736 showMode: function(dir) {
12738 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
12740 Roo.each(this.picker().select('>div',true).elements, function(v){
12741 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12744 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
12749 if(this.isInline) return;
12751 this.picker().removeClass(['bottom', 'top']);
12753 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
12755 * place to the top of element!
12759 this.picker().addClass('top');
12760 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12765 this.picker().addClass('bottom');
12767 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12770 parseDate : function(value){
12771 if(!value || value instanceof Date){
12774 var v = Date.parseDate(value, this.format);
12775 if (!v && this.useIso) {
12776 v = Date.parseDate(value, 'Y-m-d');
12778 if(!v && this.altFormats){
12779 if(!this.altFormatsArray){
12780 this.altFormatsArray = this.altFormats.split("|");
12782 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
12783 v = Date.parseDate(value, this.altFormatsArray[i]);
12789 formatDate : function(date, fmt){
12790 return (!date || !(date instanceof Date)) ?
12791 date : date.dateFormat(fmt || this.format);
12794 onFocus : function()
12796 Roo.bootstrap.DateField.superclass.onFocus.call(this);
12800 onBlur : function()
12802 Roo.bootstrap.DateField.superclass.onBlur.call(this);
12808 this.picker().show();
12812 this.fireEvent('show', this, this.date);
12817 if(this.isInline) return;
12818 this.picker().hide();
12819 this.viewMode = this.startViewMode;
12822 this.fireEvent('hide', this, this.date);
12826 onMousedown: function(e){
12827 e.stopPropagation();
12828 e.preventDefault();
12831 keyup: function(e){
12832 Roo.bootstrap.DateField.superclass.keyup.call(this);
12837 setValue: function(v){
12838 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
12840 this.fireEvent('select', this, this.date);
12844 fireKey: function(e){
12845 if (!this.picker().isVisible()){
12846 if (e.keyCode == 27) // allow escape to hide and re-show picker
12850 var dateChanged = false,
12852 newDate, newViewDate;
12856 e.preventDefault();
12860 if (!this.keyboardNavigation) break;
12861 dir = e.keyCode == 37 ? -1 : 1;
12864 newDate = this.moveYear(this.date, dir);
12865 newViewDate = this.moveYear(this.viewDate, dir);
12866 } else if (e.shiftKey){
12867 newDate = this.moveMonth(this.date, dir);
12868 newViewDate = this.moveMonth(this.viewDate, dir);
12870 newDate = new Date(this.date);
12871 newDate.setUTCDate(this.date.getUTCDate() + dir);
12872 newViewDate = new Date(this.viewDate);
12873 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
12875 if (this.dateWithinRange(newDate)){
12876 this.date = newDate;
12877 this.viewDate = newViewDate;
12878 this.setValue(this.formatDate(this.date));
12880 e.preventDefault();
12881 dateChanged = true;
12886 if (!this.keyboardNavigation) break;
12887 dir = e.keyCode == 38 ? -1 : 1;
12889 newDate = this.moveYear(this.date, dir);
12890 newViewDate = this.moveYear(this.viewDate, dir);
12891 } else if (e.shiftKey){
12892 newDate = this.moveMonth(this.date, dir);
12893 newViewDate = this.moveMonth(this.viewDate, dir);
12895 newDate = new Date(this.date);
12896 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
12897 newViewDate = new Date(this.viewDate);
12898 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
12900 if (this.dateWithinRange(newDate)){
12901 this.date = newDate;
12902 this.viewDate = newViewDate;
12903 this.setValue(this.formatDate(this.date));
12905 e.preventDefault();
12906 dateChanged = true;
12910 this.setValue(this.formatDate(this.date));
12912 e.preventDefault();
12915 this.setValue(this.formatDate(this.date));
12922 onClick: function(e) {
12923 e.stopPropagation();
12924 e.preventDefault();
12926 var target = e.getTarget();
12928 if(target.nodeName.toLowerCase() === 'i'){
12929 target = Roo.get(target).dom.parentNode;
12932 var nodeName = target.nodeName;
12933 var className = target.className;
12934 var html = target.innerHTML;
12936 switch(nodeName.toLowerCase()) {
12938 switch(className) {
12944 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
12945 switch(this.viewMode){
12947 this.viewDate = this.moveMonth(this.viewDate, dir);
12951 this.viewDate = this.moveYear(this.viewDate, dir);
12957 var date = new Date();
12958 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
12960 this.setValue(this.formatDate(this.date));
12966 if (className.indexOf('disabled') === -1) {
12967 this.viewDate.setUTCDate(1);
12968 if (className.indexOf('month') !== -1) {
12969 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
12971 var year = parseInt(html, 10) || 0;
12972 this.viewDate.setUTCFullYear(year);
12981 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
12982 var day = parseInt(html, 10) || 1;
12983 var year = this.viewDate.getUTCFullYear(),
12984 month = this.viewDate.getUTCMonth();
12986 if (className.indexOf('old') !== -1) {
12993 } else if (className.indexOf('new') !== -1) {
13001 this.date = this.UTCDate(year, month, day,0,0,0,0);
13002 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
13004 this.setValue(this.formatDate(this.date));
13011 setStartDate: function(startDate){
13012 this.startDate = startDate || -Infinity;
13013 if (this.startDate !== -Infinity) {
13014 this.startDate = this.parseDate(this.startDate);
13017 this.updateNavArrows();
13020 setEndDate: function(endDate){
13021 this.endDate = endDate || Infinity;
13022 if (this.endDate !== Infinity) {
13023 this.endDate = this.parseDate(this.endDate);
13026 this.updateNavArrows();
13029 setDaysOfWeekDisabled: function(daysOfWeekDisabled){
13030 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
13031 if (typeof(this.daysOfWeekDisabled) !== 'object') {
13032 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
13034 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
13035 return parseInt(d, 10);
13038 this.updateNavArrows();
13041 updateNavArrows: function() {
13042 var d = new Date(this.viewDate),
13043 year = d.getUTCFullYear(),
13044 month = d.getUTCMonth();
13046 Roo.each(this.picker().select('.prev', true).elements, function(v){
13048 switch (this.viewMode) {
13051 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
13057 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
13064 Roo.each(this.picker().select('.next', true).elements, function(v){
13066 switch (this.viewMode) {
13069 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
13075 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
13083 moveMonth: function(date, dir){
13084 if (!dir) return date;
13085 var new_date = new Date(date.valueOf()),
13086 day = new_date.getUTCDate(),
13087 month = new_date.getUTCMonth(),
13088 mag = Math.abs(dir),
13090 dir = dir > 0 ? 1 : -1;
13093 // If going back one month, make sure month is not current month
13094 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
13096 return new_date.getUTCMonth() == month;
13098 // If going forward one month, make sure month is as expected
13099 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
13101 return new_date.getUTCMonth() != new_month;
13103 new_month = month + dir;
13104 new_date.setUTCMonth(new_month);
13105 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
13106 if (new_month < 0 || new_month > 11)
13107 new_month = (new_month + 12) % 12;
13109 // For magnitudes >1, move one month at a time...
13110 for (var i=0; i<mag; i++)
13111 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
13112 new_date = this.moveMonth(new_date, dir);
13113 // ...then reset the day, keeping it in the new month
13114 new_month = new_date.getUTCMonth();
13115 new_date.setUTCDate(day);
13117 return new_month != new_date.getUTCMonth();
13120 // Common date-resetting loop -- if date is beyond end of month, make it
13123 new_date.setUTCDate(--day);
13124 new_date.setUTCMonth(new_month);
13129 moveYear: function(date, dir){
13130 return this.moveMonth(date, dir*12);
13133 dateWithinRange: function(date){
13134 return date >= this.startDate && date <= this.endDate;
13138 remove: function() {
13139 this.picker().remove();
13144 Roo.apply(Roo.bootstrap.DateField, {
13155 html: '<i class="icon-arrow-left"/>'
13165 html: '<i class="icon-arrow-right"/>'
13207 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
13208 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
13209 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
13210 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
13211 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
13224 navFnc: 'FullYear',
13229 navFnc: 'FullYear',
13234 Roo.apply(Roo.bootstrap.DateField, {
13238 cls: 'datepicker dropdown-menu',
13242 cls: 'datepicker-days',
13246 cls: 'table-condensed',
13248 Roo.bootstrap.DateField.head,
13252 Roo.bootstrap.DateField.footer
13259 cls: 'datepicker-months',
13263 cls: 'table-condensed',
13265 Roo.bootstrap.DateField.head,
13266 Roo.bootstrap.DateField.content,
13267 Roo.bootstrap.DateField.footer
13274 cls: 'datepicker-years',
13278 cls: 'table-condensed',
13280 Roo.bootstrap.DateField.head,
13281 Roo.bootstrap.DateField.content,
13282 Roo.bootstrap.DateField.footer
13301 * @class Roo.bootstrap.TimeField
13302 * @extends Roo.bootstrap.Input
13303 * Bootstrap DateField class
13307 * Create a new TimeField
13308 * @param {Object} config The config object
13311 Roo.bootstrap.TimeField = function(config){
13312 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
13316 * Fires when this field show.
13317 * @param {Roo.bootstrap.DateField} this
13318 * @param {Mixed} date The date value
13323 * Fires when this field hide.
13324 * @param {Roo.bootstrap.DateField} this
13325 * @param {Mixed} date The date value
13330 * Fires when select a date.
13331 * @param {Roo.bootstrap.DateField} this
13332 * @param {Mixed} date The date value
13338 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
13341 * @cfg {String} format
13342 * The default time format string which can be overriden for localization support. The format must be
13343 * valid according to {@link Date#parseDate} (defaults to 'H:i').
13347 onRender: function(ct, position)
13350 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
13352 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
13354 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13356 this.pop = this.picker().select('>.datepicker-time',true).first();
13357 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
13359 this.picker().on('mousedown', this.onMousedown, this);
13360 this.picker().on('click', this.onClick, this);
13362 this.picker().addClass('datepicker-dropdown');
13367 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
13368 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
13369 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
13370 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
13371 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
13372 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
13376 fireKey: function(e){
13377 if (!this.picker().isVisible()){
13378 if (e.keyCode == 27) // allow escape to hide and re-show picker
13383 e.preventDefault();
13391 this.onTogglePeriod();
13394 this.onIncrementMinutes();
13397 this.onDecrementMinutes();
13406 onClick: function(e) {
13407 e.stopPropagation();
13408 e.preventDefault();
13411 picker : function()
13413 return this.el.select('.datepicker', true).first();
13416 fillTime: function()
13418 var time = this.pop.select('tbody', true).first();
13420 time.dom.innerHTML = '';
13435 cls: 'hours-up glyphicon glyphicon-chevron-up'
13455 cls: 'minutes-up glyphicon glyphicon-chevron-up'
13476 cls: 'timepicker-hour',
13491 cls: 'timepicker-minute',
13506 cls: 'btn btn-primary period',
13528 cls: 'hours-down glyphicon glyphicon-chevron-down'
13548 cls: 'minutes-down glyphicon glyphicon-chevron-down'
13566 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
13573 var hours = this.time.getHours();
13574 var minutes = this.time.getMinutes();
13587 hours = hours - 12;
13591 hours = '0' + hours;
13595 minutes = '0' + minutes;
13598 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
13599 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
13600 this.pop.select('button', true).first().dom.innerHTML = period;
13606 this.picker().removeClass(['bottom', 'top']);
13608 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
13610 * place to the top of element!
13614 this.picker().addClass('top');
13615 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13620 this.picker().addClass('bottom');
13622 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13625 onFocus : function()
13627 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
13631 onBlur : function()
13633 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
13639 this.picker().show();
13644 this.fireEvent('show', this, this.date);
13649 this.picker().hide();
13652 this.fireEvent('hide', this, this.date);
13655 setTime : function()
13658 this.setValue(this.time.format(this.format));
13660 this.fireEvent('select', this, this.date);
13665 onMousedown: function(e){
13666 e.stopPropagation();
13667 e.preventDefault();
13670 onIncrementHours: function()
13672 Roo.log('onIncrementHours');
13673 this.time = this.time.add(Date.HOUR, 1);
13678 onDecrementHours: function()
13680 Roo.log('onDecrementHours');
13681 this.time = this.time.add(Date.HOUR, -1);
13685 onIncrementMinutes: function()
13687 Roo.log('onIncrementMinutes');
13688 this.time = this.time.add(Date.MINUTE, 1);
13692 onDecrementMinutes: function()
13694 Roo.log('onDecrementMinutes');
13695 this.time = this.time.add(Date.MINUTE, -1);
13699 onTogglePeriod: function()
13701 Roo.log('onTogglePeriod');
13702 this.time = this.time.add(Date.HOUR, 12);
13709 Roo.apply(Roo.bootstrap.TimeField, {
13739 cls: 'btn btn-info ok',
13751 Roo.apply(Roo.bootstrap.TimeField, {
13755 cls: 'datepicker dropdown-menu',
13759 cls: 'datepicker-time',
13763 cls: 'table-condensed',
13765 Roo.bootstrap.TimeField.content,
13766 Roo.bootstrap.TimeField.footer
13785 * @class Roo.bootstrap.CheckBox
13786 * @extends Roo.bootstrap.Input
13787 * Bootstrap CheckBox class
13789 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
13790 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
13791 * @cfg {String} boxLabel The text that appears beside the checkbox
13792 * @cfg {Boolean} checked initnal the element
13795 * Create a new CheckBox
13796 * @param {Object} config The config object
13799 Roo.bootstrap.CheckBox = function(config){
13800 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
13805 * Fires when the element is checked or unchecked.
13806 * @param {Roo.bootstrap.CheckBox} this This input
13807 * @param {Boolean} checked The new checked value
13813 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
13815 inputType: 'checkbox',
13821 getAutoCreate : function()
13823 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
13829 cfg.cls = 'form-group' //input-group
13834 type : this.inputType,
13835 value : (!this.checked) ? this.valueOff : this.inputValue,
13837 placeholder : this.placeholder || ''
13841 if (this.disabled) {
13842 input.disabled=true;
13846 input.checked = this.checked;
13850 input.name = this.name;
13854 input.cls += ' input-' + this.size;
13858 ['xs','sm','md','lg'].map(function(size){
13859 if (settings[size]) {
13860 cfg.cls += ' col-' + size + '-' + settings[size];
13864 var inputblock = input;
13866 if (this.before || this.after) {
13869 cls : 'input-group',
13873 inputblock.cn.push({
13875 cls : 'input-group-addon',
13879 inputblock.cn.push(input);
13881 inputblock.cn.push({
13883 cls : 'input-group-addon',
13890 if (align ==='left' && this.fieldLabel.length) {
13891 Roo.log("left and has label");
13897 cls : 'control-label col-md-' + this.labelWidth,
13898 html : this.fieldLabel
13902 cls : "col-md-" + (12 - this.labelWidth),
13909 } else if ( this.fieldLabel.length) {
13914 tag: this.boxLabel ? 'span' : 'label',
13916 cls: 'control-label box-input-label',
13917 //cls : 'input-group-addon',
13918 html : this.fieldLabel
13928 Roo.log(" no label && no align");
13943 html: this.boxLabel
13952 * return the real input element.
13954 inputEl: function ()
13956 return this.el.select('input.form-box',true).first();
13961 return this.el.select('label.control-label',true).first();
13964 initEvents : function()
13966 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
13968 this.inputEl().on('click', this.onClick, this);
13972 onClick : function()
13974 this.setChecked(!this.checked);
13977 setChecked : function(state,suppressEvent)
13979 this.checked = state;
13981 this.inputEl().dom.checked = state;
13983 if(suppressEvent !== true){
13984 this.fireEvent('check', this, state);
13987 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
13991 setValue : function(v,suppressEvent)
13993 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
14007 * @class Roo.bootstrap.Radio
14008 * @extends Roo.bootstrap.CheckBox
14009 * Bootstrap Radio class
14012 * Create a new Radio
14013 * @param {Object} config The config object
14016 Roo.bootstrap.Radio = function(config){
14017 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
14021 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
14023 inputType: 'radio',
14027 getAutoCreate : function()
14029 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
14035 cfg.cls = 'form-group' //input-group
14040 type : this.inputType,
14041 value : (!this.checked) ? this.valueOff : this.inputValue,
14043 placeholder : this.placeholder || ''
14047 if (this.disabled) {
14048 input.disabled=true;
14052 input.checked = this.checked;
14056 input.name = this.name;
14060 input.cls += ' input-' + this.size;
14064 ['xs','sm','md','lg'].map(function(size){
14065 if (settings[size]) {
14066 cfg.cls += ' col-' + size + '-' + settings[size];
14070 var inputblock = input;
14072 if (this.before || this.after) {
14075 cls : 'input-group',
14079 inputblock.cn.push({
14081 cls : 'input-group-addon',
14085 inputblock.cn.push(input);
14087 inputblock.cn.push({
14089 cls : 'input-group-addon',
14096 if (align ==='left' && this.fieldLabel.length) {
14097 Roo.log("left and has label");
14103 cls : 'control-label col-md-' + this.labelWidth,
14104 html : this.fieldLabel
14108 cls : "col-md-" + (12 - this.labelWidth),
14115 } else if ( this.fieldLabel.length) {
14122 cls: 'control-label box-input-label',
14123 //cls : 'input-group-addon',
14124 html : this.fieldLabel
14134 Roo.log(" no label && no align");
14149 html: this.boxLabel
14157 onClick : function()
14159 this.setChecked(true);
14162 setChecked : function(state,suppressEvent)
14165 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
14166 v.dom.checked = false;
14170 this.checked = state;
14171 this.inputEl().dom.checked = state;
14173 if(suppressEvent !== true){
14174 this.fireEvent('check', this, state);
14177 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
14181 getGroupValue : function()
14184 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
14185 if(v.dom.checked == true){
14186 value = v.dom.value;
14194 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
14195 * @return {Mixed} value The field value
14197 getValue : function(){
14198 return this.getGroupValue();
14204 //<script type="text/javascript">
14207 * Based Ext JS Library 1.1.1
14208 * Copyright(c) 2006-2007, Ext JS, LLC.
14214 * @class Roo.HtmlEditorCore
14215 * @extends Roo.Component
14216 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
14218 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
14221 Roo.HtmlEditorCore = function(config){
14224 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
14227 * @event initialize
14228 * Fires when the editor is fully initialized (including the iframe)
14229 * @param {Roo.HtmlEditorCore} this
14234 * Fires when the editor is first receives the focus. Any insertion must wait
14235 * until after this event.
14236 * @param {Roo.HtmlEditorCore} this
14240 * @event beforesync
14241 * Fires before the textarea is updated with content from the editor iframe. Return false
14242 * to cancel the sync.
14243 * @param {Roo.HtmlEditorCore} this
14244 * @param {String} html
14248 * @event beforepush
14249 * Fires before the iframe editor is updated with content from the textarea. Return false
14250 * to cancel the push.
14251 * @param {Roo.HtmlEditorCore} this
14252 * @param {String} html
14257 * Fires when the textarea is updated with content from the editor iframe.
14258 * @param {Roo.HtmlEditorCore} this
14259 * @param {String} html
14264 * Fires when the iframe editor is updated with content from the textarea.
14265 * @param {Roo.HtmlEditorCore} this
14266 * @param {String} html
14271 * @event editorevent
14272 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
14273 * @param {Roo.HtmlEditorCore} this
14281 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
14285 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
14291 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
14296 * @cfg {Number} height (in pixels)
14300 * @cfg {Number} width (in pixels)
14305 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
14308 stylesheets: false,
14313 // private properties
14314 validationEvent : false,
14316 initialized : false,
14318 sourceEditMode : false,
14319 onFocus : Roo.emptyFn,
14321 hideMode:'offsets',
14329 * Protected method that will not generally be called directly. It
14330 * is called when the editor initializes the iframe with HTML contents. Override this method if you
14331 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
14333 getDocMarkup : function(){
14336 Roo.log(this.stylesheets);
14338 // inherit styels from page...??
14339 if (this.stylesheets === false) {
14341 Roo.get(document.head).select('style').each(function(node) {
14342 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
14345 Roo.get(document.head).select('link').each(function(node) {
14346 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
14349 } else if (!this.stylesheets.length) {
14351 st = '<style type="text/css">' +
14352 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
14355 Roo.each(this.stylesheets, function(s) {
14356 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
14361 st += '<style type="text/css">' +
14362 'IMG { cursor: pointer } ' +
14366 return '<html><head>' + st +
14367 //<style type="text/css">' +
14368 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
14370 ' </head><body class="roo-htmleditor-body"></body></html>';
14374 onRender : function(ct, position)
14377 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
14378 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
14381 this.el.dom.style.border = '0 none';
14382 this.el.dom.setAttribute('tabIndex', -1);
14383 this.el.addClass('x-hidden hide');
14387 if(Roo.isIE){ // fix IE 1px bogus margin
14388 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
14392 this.frameId = Roo.id();
14396 var iframe = this.owner.wrap.createChild({
14398 cls: 'form-control', // bootstrap..
14400 name: this.frameId,
14401 frameBorder : 'no',
14402 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
14407 this.iframe = iframe.dom;
14409 this.assignDocWin();
14411 this.doc.designMode = 'on';
14414 this.doc.write(this.getDocMarkup());
14418 var task = { // must defer to wait for browser to be ready
14420 //console.log("run task?" + this.doc.readyState);
14421 this.assignDocWin();
14422 if(this.doc.body || this.doc.readyState == 'complete'){
14424 this.doc.designMode="on";
14428 Roo.TaskMgr.stop(task);
14429 this.initEditor.defer(10, this);
14436 Roo.TaskMgr.start(task);
14443 onResize : function(w, h)
14445 Roo.log('resize: ' +w + ',' + h );
14446 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
14450 if(typeof w == 'number'){
14452 this.iframe.style.width = w + 'px';
14454 if(typeof h == 'number'){
14456 this.iframe.style.height = h + 'px';
14458 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
14465 * Toggles the editor between standard and source edit mode.
14466 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
14468 toggleSourceEdit : function(sourceEditMode){
14470 this.sourceEditMode = sourceEditMode === true;
14472 if(this.sourceEditMode){
14474 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
14477 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
14478 //this.iframe.className = '';
14481 //this.setSize(this.owner.wrap.getSize());
14482 //this.fireEvent('editmodechange', this, this.sourceEditMode);
14489 * Protected method that will not generally be called directly. If you need/want
14490 * custom HTML cleanup, this is the method you should override.
14491 * @param {String} html The HTML to be cleaned
14492 * return {String} The cleaned HTML
14494 cleanHtml : function(html){
14495 html = String(html);
14496 if(html.length > 5){
14497 if(Roo.isSafari){ // strip safari nonsense
14498 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
14501 if(html == ' '){
14508 * HTML Editor -> Textarea
14509 * Protected method that will not generally be called directly. Syncs the contents
14510 * of the editor iframe with the textarea.
14512 syncValue : function(){
14513 if(this.initialized){
14514 var bd = (this.doc.body || this.doc.documentElement);
14515 //this.cleanUpPaste(); -- this is done else where and causes havoc..
14516 var html = bd.innerHTML;
14518 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
14519 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
14521 html = '<div style="'+m[0]+'">' + html + '</div>';
14524 html = this.cleanHtml(html);
14525 // fix up the special chars.. normaly like back quotes in word...
14526 // however we do not want to do this with chinese..
14527 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
14528 var cc = b.charCodeAt();
14530 (cc >= 0x4E00 && cc < 0xA000 ) ||
14531 (cc >= 0x3400 && cc < 0x4E00 ) ||
14532 (cc >= 0xf900 && cc < 0xfb00 )
14538 if(this.owner.fireEvent('beforesync', this, html) !== false){
14539 this.el.dom.value = html;
14540 this.owner.fireEvent('sync', this, html);
14546 * Protected method that will not generally be called directly. Pushes the value of the textarea
14547 * into the iframe editor.
14549 pushValue : function(){
14550 if(this.initialized){
14551 var v = this.el.dom.value.trim();
14553 // if(v.length < 1){
14557 if(this.owner.fireEvent('beforepush', this, v) !== false){
14558 var d = (this.doc.body || this.doc.documentElement);
14560 this.cleanUpPaste();
14561 this.el.dom.value = d.innerHTML;
14562 this.owner.fireEvent('push', this, v);
14568 deferFocus : function(){
14569 this.focus.defer(10, this);
14573 focus : function(){
14574 if(this.win && !this.sourceEditMode){
14581 assignDocWin: function()
14583 var iframe = this.iframe;
14586 this.doc = iframe.contentWindow.document;
14587 this.win = iframe.contentWindow;
14589 if (!Roo.get(this.frameId)) {
14592 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
14593 this.win = Roo.get(this.frameId).dom.contentWindow;
14598 initEditor : function(){
14599 //console.log("INIT EDITOR");
14600 this.assignDocWin();
14604 this.doc.designMode="on";
14606 this.doc.write(this.getDocMarkup());
14609 var dbody = (this.doc.body || this.doc.documentElement);
14610 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
14611 // this copies styles from the containing element into thsi one..
14612 // not sure why we need all of this..
14613 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
14614 ss['background-attachment'] = 'fixed'; // w3c
14615 dbody.bgProperties = 'fixed'; // ie
14616 Roo.DomHelper.applyStyles(dbody, ss);
14617 Roo.EventManager.on(this.doc, {
14618 //'mousedown': this.onEditorEvent,
14619 'mouseup': this.onEditorEvent,
14620 'dblclick': this.onEditorEvent,
14621 'click': this.onEditorEvent,
14622 'keyup': this.onEditorEvent,
14627 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
14629 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
14630 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
14632 this.initialized = true;
14634 this.owner.fireEvent('initialize', this);
14639 onDestroy : function(){
14645 //for (var i =0; i < this.toolbars.length;i++) {
14646 // // fixme - ask toolbars for heights?
14647 // this.toolbars[i].onDestroy();
14650 //this.wrap.dom.innerHTML = '';
14651 //this.wrap.remove();
14656 onFirstFocus : function(){
14658 this.assignDocWin();
14661 this.activated = true;
14664 if(Roo.isGecko){ // prevent silly gecko errors
14666 var s = this.win.getSelection();
14667 if(!s.focusNode || s.focusNode.nodeType != 3){
14668 var r = s.getRangeAt(0);
14669 r.selectNodeContents((this.doc.body || this.doc.documentElement));
14674 this.execCmd('useCSS', true);
14675 this.execCmd('styleWithCSS', false);
14678 this.owner.fireEvent('activate', this);
14682 adjustFont: function(btn){
14683 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
14684 //if(Roo.isSafari){ // safari
14687 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
14688 if(Roo.isSafari){ // safari
14689 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
14690 v = (v < 10) ? 10 : v;
14691 v = (v > 48) ? 48 : v;
14692 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
14697 v = Math.max(1, v+adjust);
14699 this.execCmd('FontSize', v );
14702 onEditorEvent : function(e){
14703 this.owner.fireEvent('editorevent', this, e);
14704 // this.updateToolbar();
14705 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
14708 insertTag : function(tg)
14710 // could be a bit smarter... -> wrap the current selected tRoo..
14711 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
14713 range = this.createRange(this.getSelection());
14714 var wrappingNode = this.doc.createElement(tg.toLowerCase());
14715 wrappingNode.appendChild(range.extractContents());
14716 range.insertNode(wrappingNode);
14723 this.execCmd("formatblock", tg);
14727 insertText : function(txt)
14731 var range = this.createRange();
14732 range.deleteContents();
14733 //alert(Sender.getAttribute('label'));
14735 range.insertNode(this.doc.createTextNode(txt));
14741 * Executes a Midas editor command on the editor document and performs necessary focus and
14742 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
14743 * @param {String} cmd The Midas command
14744 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
14746 relayCmd : function(cmd, value){
14748 this.execCmd(cmd, value);
14749 this.owner.fireEvent('editorevent', this);
14750 //this.updateToolbar();
14751 this.owner.deferFocus();
14755 * Executes a Midas editor command directly on the editor document.
14756 * For visual commands, you should use {@link #relayCmd} instead.
14757 * <b>This should only be called after the editor is initialized.</b>
14758 * @param {String} cmd The Midas command
14759 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
14761 execCmd : function(cmd, value){
14762 this.doc.execCommand(cmd, false, value === undefined ? null : value);
14769 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
14771 * @param {String} text | dom node..
14773 insertAtCursor : function(text)
14778 if(!this.activated){
14784 var r = this.doc.selection.createRange();
14795 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
14799 // from jquery ui (MIT licenced)
14801 var win = this.win;
14803 if (win.getSelection && win.getSelection().getRangeAt) {
14804 range = win.getSelection().getRangeAt(0);
14805 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
14806 range.insertNode(node);
14807 } else if (win.document.selection && win.document.selection.createRange) {
14808 // no firefox support
14809 var txt = typeof(text) == 'string' ? text : text.outerHTML;
14810 win.document.selection.createRange().pasteHTML(txt);
14812 // no firefox support
14813 var txt = typeof(text) == 'string' ? text : text.outerHTML;
14814 this.execCmd('InsertHTML', txt);
14823 mozKeyPress : function(e){
14825 var c = e.getCharCode(), cmd;
14828 c = String.fromCharCode(c).toLowerCase();
14842 this.cleanUpPaste.defer(100, this);
14850 e.preventDefault();
14858 fixKeys : function(){ // load time branching for fastest keydown performance
14860 return function(e){
14861 var k = e.getKey(), r;
14864 r = this.doc.selection.createRange();
14867 r.pasteHTML('    ');
14874 r = this.doc.selection.createRange();
14876 var target = r.parentElement();
14877 if(!target || target.tagName.toLowerCase() != 'li'){
14879 r.pasteHTML('<br />');
14885 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
14886 this.cleanUpPaste.defer(100, this);
14892 }else if(Roo.isOpera){
14893 return function(e){
14894 var k = e.getKey();
14898 this.execCmd('InsertHTML','    ');
14901 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
14902 this.cleanUpPaste.defer(100, this);
14907 }else if(Roo.isSafari){
14908 return function(e){
14909 var k = e.getKey();
14913 this.execCmd('InsertText','\t');
14917 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
14918 this.cleanUpPaste.defer(100, this);
14926 getAllAncestors: function()
14928 var p = this.getSelectedNode();
14931 a.push(p); // push blank onto stack..
14932 p = this.getParentElement();
14936 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
14940 a.push(this.doc.body);
14944 lastSelNode : false,
14947 getSelection : function()
14949 this.assignDocWin();
14950 return Roo.isIE ? this.doc.selection : this.win.getSelection();
14953 getSelectedNode: function()
14955 // this may only work on Gecko!!!
14957 // should we cache this!!!!
14962 var range = this.createRange(this.getSelection()).cloneRange();
14965 var parent = range.parentElement();
14967 var testRange = range.duplicate();
14968 testRange.moveToElementText(parent);
14969 if (testRange.inRange(range)) {
14972 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
14975 parent = parent.parentElement;
14980 // is ancestor a text element.
14981 var ac = range.commonAncestorContainer;
14982 if (ac.nodeType == 3) {
14983 ac = ac.parentNode;
14986 var ar = ac.childNodes;
14989 var other_nodes = [];
14990 var has_other_nodes = false;
14991 for (var i=0;i<ar.length;i++) {
14992 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
14995 // fullly contained node.
14997 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
15002 // probably selected..
15003 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
15004 other_nodes.push(ar[i]);
15008 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
15013 has_other_nodes = true;
15015 if (!nodes.length && other_nodes.length) {
15016 nodes= other_nodes;
15018 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
15024 createRange: function(sel)
15026 // this has strange effects when using with
15027 // top toolbar - not sure if it's a great idea.
15028 //this.editor.contentWindow.focus();
15029 if (typeof sel != "undefined") {
15031 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
15033 return this.doc.createRange();
15036 return this.doc.createRange();
15039 getParentElement: function()
15042 this.assignDocWin();
15043 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
15045 var range = this.createRange(sel);
15048 var p = range.commonAncestorContainer;
15049 while (p.nodeType == 3) { // text node
15060 * Range intersection.. the hard stuff...
15064 * [ -- selected range --- ]
15068 * if end is before start or hits it. fail.
15069 * if start is after end or hits it fail.
15071 * if either hits (but other is outside. - then it's not
15077 // @see http://www.thismuchiknow.co.uk/?p=64.
15078 rangeIntersectsNode : function(range, node)
15080 var nodeRange = node.ownerDocument.createRange();
15082 nodeRange.selectNode(node);
15084 nodeRange.selectNodeContents(node);
15087 var rangeStartRange = range.cloneRange();
15088 rangeStartRange.collapse(true);
15090 var rangeEndRange = range.cloneRange();
15091 rangeEndRange.collapse(false);
15093 var nodeStartRange = nodeRange.cloneRange();
15094 nodeStartRange.collapse(true);
15096 var nodeEndRange = nodeRange.cloneRange();
15097 nodeEndRange.collapse(false);
15099 return rangeStartRange.compareBoundaryPoints(
15100 Range.START_TO_START, nodeEndRange) == -1 &&
15101 rangeEndRange.compareBoundaryPoints(
15102 Range.START_TO_START, nodeStartRange) == 1;
15106 rangeCompareNode : function(range, node)
15108 var nodeRange = node.ownerDocument.createRange();
15110 nodeRange.selectNode(node);
15112 nodeRange.selectNodeContents(node);
15116 range.collapse(true);
15118 nodeRange.collapse(true);
15120 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
15121 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
15123 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
15125 var nodeIsBefore = ss == 1;
15126 var nodeIsAfter = ee == -1;
15128 if (nodeIsBefore && nodeIsAfter)
15130 if (!nodeIsBefore && nodeIsAfter)
15131 return 1; //right trailed.
15133 if (nodeIsBefore && !nodeIsAfter)
15134 return 2; // left trailed.
15139 // private? - in a new class?
15140 cleanUpPaste : function()
15142 // cleans up the whole document..
15143 Roo.log('cleanuppaste');
15145 this.cleanUpChildren(this.doc.body);
15146 var clean = this.cleanWordChars(this.doc.body.innerHTML);
15147 if (clean != this.doc.body.innerHTML) {
15148 this.doc.body.innerHTML = clean;
15153 cleanWordChars : function(input) {// change the chars to hex code
15154 var he = Roo.HtmlEditorCore;
15156 var output = input;
15157 Roo.each(he.swapCodes, function(sw) {
15158 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
15160 output = output.replace(swapper, sw[1]);
15167 cleanUpChildren : function (n)
15169 if (!n.childNodes.length) {
15172 for (var i = n.childNodes.length-1; i > -1 ; i--) {
15173 this.cleanUpChild(n.childNodes[i]);
15180 cleanUpChild : function (node)
15183 //console.log(node);
15184 if (node.nodeName == "#text") {
15185 // clean up silly Windows -- stuff?
15188 if (node.nodeName == "#comment") {
15189 node.parentNode.removeChild(node);
15190 // clean up silly Windows -- stuff?
15194 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
15196 node.parentNode.removeChild(node);
15201 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
15203 // remove <a name=....> as rendering on yahoo mailer is borked with this.
15204 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
15206 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
15207 // remove_keep_children = true;
15210 if (remove_keep_children) {
15211 this.cleanUpChildren(node);
15212 // inserts everything just before this node...
15213 while (node.childNodes.length) {
15214 var cn = node.childNodes[0];
15215 node.removeChild(cn);
15216 node.parentNode.insertBefore(cn, node);
15218 node.parentNode.removeChild(node);
15222 if (!node.attributes || !node.attributes.length) {
15223 this.cleanUpChildren(node);
15227 function cleanAttr(n,v)
15230 if (v.match(/^\./) || v.match(/^\//)) {
15233 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
15236 if (v.match(/^#/)) {
15239 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
15240 node.removeAttribute(n);
15244 function cleanStyle(n,v)
15246 if (v.match(/expression/)) { //XSS?? should we even bother..
15247 node.removeAttribute(n);
15250 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
15251 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
15254 var parts = v.split(/;/);
15257 Roo.each(parts, function(p) {
15258 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
15262 var l = p.split(':').shift().replace(/\s+/g,'');
15263 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
15265 if ( cblack.indexOf(l) > -1) {
15266 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
15267 //node.removeAttribute(n);
15271 // only allow 'c whitelisted system attributes'
15272 if ( cwhite.length && cwhite.indexOf(l) < 0) {
15273 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
15274 //node.removeAttribute(n);
15284 if (clean.length) {
15285 node.setAttribute(n, clean.join(';'));
15287 node.removeAttribute(n);
15293 for (var i = node.attributes.length-1; i > -1 ; i--) {
15294 var a = node.attributes[i];
15297 if (a.name.toLowerCase().substr(0,2)=='on') {
15298 node.removeAttribute(a.name);
15301 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
15302 node.removeAttribute(a.name);
15305 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
15306 cleanAttr(a.name,a.value); // fixme..
15309 if (a.name == 'style') {
15310 cleanStyle(a.name,a.value);
15313 /// clean up MS crap..
15314 // tecnically this should be a list of valid class'es..
15317 if (a.name == 'class') {
15318 if (a.value.match(/^Mso/)) {
15319 node.className = '';
15322 if (a.value.match(/body/)) {
15323 node.className = '';
15334 this.cleanUpChildren(node);
15339 * Clean up MS wordisms...
15341 cleanWord : function(node)
15344 var cleanWordChildren = function()
15346 if (!node.childNodes.length) {
15349 for (var i = node.childNodes.length-1; i > -1 ; i--) {
15350 _t.cleanWord(node.childNodes[i]);
15356 this.cleanWord(this.doc.body);
15359 if (node.nodeName == "#text") {
15360 // clean up silly Windows -- stuff?
15363 if (node.nodeName == "#comment") {
15364 node.parentNode.removeChild(node);
15365 // clean up silly Windows -- stuff?
15369 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
15370 node.parentNode.removeChild(node);
15374 // remove - but keep children..
15375 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
15376 while (node.childNodes.length) {
15377 var cn = node.childNodes[0];
15378 node.removeChild(cn);
15379 node.parentNode.insertBefore(cn, node);
15381 node.parentNode.removeChild(node);
15382 cleanWordChildren();
15386 if (node.className.length) {
15388 var cn = node.className.split(/\W+/);
15390 Roo.each(cn, function(cls) {
15391 if (cls.match(/Mso[a-zA-Z]+/)) {
15396 node.className = cna.length ? cna.join(' ') : '';
15398 node.removeAttribute("class");
15402 if (node.hasAttribute("lang")) {
15403 node.removeAttribute("lang");
15406 if (node.hasAttribute("style")) {
15408 var styles = node.getAttribute("style").split(";");
15410 Roo.each(styles, function(s) {
15411 if (!s.match(/:/)) {
15414 var kv = s.split(":");
15415 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
15418 // what ever is left... we allow.
15421 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
15422 if (!nstyle.length) {
15423 node.removeAttribute('style');
15427 cleanWordChildren();
15431 domToHTML : function(currentElement, depth, nopadtext) {
15433 depth = depth || 0;
15434 nopadtext = nopadtext || false;
15436 if (!currentElement) {
15437 return this.domToHTML(this.doc.body);
15440 //Roo.log(currentElement);
15442 var allText = false;
15443 var nodeName = currentElement.nodeName;
15444 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
15446 if (nodeName == '#text') {
15447 return currentElement.nodeValue;
15452 if (nodeName != 'BODY') {
15455 // Prints the node tagName, such as <A>, <IMG>, etc
15458 for(i = 0; i < currentElement.attributes.length;i++) {
15460 var aname = currentElement.attributes.item(i).name;
15461 if (!currentElement.attributes.item(i).value.length) {
15464 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
15467 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
15476 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
15479 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
15484 // Traverse the tree
15486 var currentElementChild = currentElement.childNodes.item(i);
15487 var allText = true;
15488 var innerHTML = '';
15490 while (currentElementChild) {
15491 // Formatting code (indent the tree so it looks nice on the screen)
15492 var nopad = nopadtext;
15493 if (lastnode == 'SPAN') {
15497 if (currentElementChild.nodeName == '#text') {
15498 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
15499 if (!nopad && toadd.length > 80) {
15500 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
15502 innerHTML += toadd;
15505 currentElementChild = currentElement.childNodes.item(i);
15511 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
15513 // Recursively traverse the tree structure of the child node
15514 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
15515 lastnode = currentElementChild.nodeName;
15517 currentElementChild=currentElement.childNodes.item(i);
15523 // The remaining code is mostly for formatting the tree
15524 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
15529 ret+= "</"+tagName+">";
15535 // hide stuff that is not compatible
15549 * @event specialkey
15553 * @cfg {String} fieldClass @hide
15556 * @cfg {String} focusClass @hide
15559 * @cfg {String} autoCreate @hide
15562 * @cfg {String} inputType @hide
15565 * @cfg {String} invalidClass @hide
15568 * @cfg {String} invalidText @hide
15571 * @cfg {String} msgFx @hide
15574 * @cfg {String} validateOnBlur @hide
15578 Roo.HtmlEditorCore.white = [
15579 'area', 'br', 'img', 'input', 'hr', 'wbr',
15581 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
15582 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
15583 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
15584 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
15585 'table', 'ul', 'xmp',
15587 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
15590 'dir', 'menu', 'ol', 'ul', 'dl',
15596 Roo.HtmlEditorCore.black = [
15597 // 'embed', 'object', // enable - backend responsiblity to clean thiese
15599 'base', 'basefont', 'bgsound', 'blink', 'body',
15600 'frame', 'frameset', 'head', 'html', 'ilayer',
15601 'iframe', 'layer', 'link', 'meta', 'object',
15602 'script', 'style' ,'title', 'xml' // clean later..
15604 Roo.HtmlEditorCore.clean = [
15605 'script', 'style', 'title', 'xml'
15607 Roo.HtmlEditorCore.remove = [
15612 Roo.HtmlEditorCore.ablack = [
15616 Roo.HtmlEditorCore.aclean = [
15617 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
15621 Roo.HtmlEditorCore.pwhite= [
15622 'http', 'https', 'mailto'
15625 // white listed style attributes.
15626 Roo.HtmlEditorCore.cwhite= [
15627 // 'text-align', /// default is to allow most things..
15633 // black listed style attributes.
15634 Roo.HtmlEditorCore.cblack= [
15635 // 'font-size' -- this can be set by the project
15639 Roo.HtmlEditorCore.swapCodes =[
15658 * @class Roo.bootstrap.HtmlEditor
15659 * @extends Roo.bootstrap.TextArea
15660 * Bootstrap HtmlEditor class
15663 * Create a new HtmlEditor
15664 * @param {Object} config The config object
15667 Roo.bootstrap.HtmlEditor = function(config){
15668 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
15669 if (!this.toolbars) {
15670 this.toolbars = [];
15672 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
15675 * @event initialize
15676 * Fires when the editor is fully initialized (including the iframe)
15677 * @param {HtmlEditor} this
15682 * Fires when the editor is first receives the focus. Any insertion must wait
15683 * until after this event.
15684 * @param {HtmlEditor} this
15688 * @event beforesync
15689 * Fires before the textarea is updated with content from the editor iframe. Return false
15690 * to cancel the sync.
15691 * @param {HtmlEditor} this
15692 * @param {String} html
15696 * @event beforepush
15697 * Fires before the iframe editor is updated with content from the textarea. Return false
15698 * to cancel the push.
15699 * @param {HtmlEditor} this
15700 * @param {String} html
15705 * Fires when the textarea is updated with content from the editor iframe.
15706 * @param {HtmlEditor} this
15707 * @param {String} html
15712 * Fires when the iframe editor is updated with content from the textarea.
15713 * @param {HtmlEditor} this
15714 * @param {String} html
15718 * @event editmodechange
15719 * Fires when the editor switches edit modes
15720 * @param {HtmlEditor} this
15721 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
15723 editmodechange: true,
15725 * @event editorevent
15726 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
15727 * @param {HtmlEditor} this
15731 * @event firstfocus
15732 * Fires when on first focus - needed by toolbars..
15733 * @param {HtmlEditor} this
15738 * Auto save the htmlEditor value as a file into Events
15739 * @param {HtmlEditor} this
15743 * @event savedpreview
15744 * preview the saved version of htmlEditor
15745 * @param {HtmlEditor} this
15752 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
15756 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
15761 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
15766 * @cfg {Number} height (in pixels)
15770 * @cfg {Number} width (in pixels)
15775 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
15778 stylesheets: false,
15783 // private properties
15784 validationEvent : false,
15786 initialized : false,
15789 onFocus : Roo.emptyFn,
15791 hideMode:'offsets',
15794 tbContainer : false,
15796 toolbarContainer :function() {
15797 return this.wrap.select('.x-html-editor-tb',true).first();
15801 * Protected method that will not generally be called directly. It
15802 * is called when the editor creates its toolbar. Override this method if you need to
15803 * add custom toolbar buttons.
15804 * @param {HtmlEditor} editor
15806 createToolbar : function(){
15808 Roo.log("create toolbars");
15810 this.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard({editor: this} ) ];
15811 this.toolbars[0].render(this.toolbarContainer());
15815 // if (!editor.toolbars || !editor.toolbars.length) {
15816 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
15819 // for (var i =0 ; i < editor.toolbars.length;i++) {
15820 // editor.toolbars[i] = Roo.factory(
15821 // typeof(editor.toolbars[i]) == 'string' ?
15822 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
15823 // Roo.bootstrap.HtmlEditor);
15824 // editor.toolbars[i].init(editor);
15830 onRender : function(ct, position)
15832 // Roo.log("Call onRender: " + this.xtype);
15834 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
15836 this.wrap = this.inputEl().wrap({
15837 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
15840 this.editorcore.onRender(ct, position);
15842 if (this.resizable) {
15843 this.resizeEl = new Roo.Resizable(this.wrap, {
15847 minHeight : this.height,
15848 height: this.height,
15849 handles : this.resizable,
15852 resize : function(r, w, h) {
15853 _t.onResize(w,h); // -something
15859 this.createToolbar(this);
15862 if(!this.width && this.resizable){
15863 this.setSize(this.wrap.getSize());
15865 if (this.resizeEl) {
15866 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
15867 // should trigger onReize..
15873 onResize : function(w, h)
15875 Roo.log('resize: ' +w + ',' + h );
15876 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
15880 if(this.inputEl() ){
15881 if(typeof w == 'number'){
15882 var aw = w - this.wrap.getFrameWidth('lr');
15883 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
15886 if(typeof h == 'number'){
15887 var tbh = -11; // fixme it needs to tool bar size!
15888 for (var i =0; i < this.toolbars.length;i++) {
15889 // fixme - ask toolbars for heights?
15890 tbh += this.toolbars[i].el.getHeight();
15891 //if (this.toolbars[i].footer) {
15892 // tbh += this.toolbars[i].footer.el.getHeight();
15900 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
15901 ah -= 5; // knock a few pixes off for look..
15902 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
15906 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
15907 this.editorcore.onResize(ew,eh);
15912 * Toggles the editor between standard and source edit mode.
15913 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
15915 toggleSourceEdit : function(sourceEditMode)
15917 this.editorcore.toggleSourceEdit(sourceEditMode);
15919 if(this.editorcore.sourceEditMode){
15920 Roo.log('editor - showing textarea');
15923 // Roo.log(this.syncValue());
15925 this.inputEl().removeClass('hide');
15926 this.inputEl().dom.removeAttribute('tabIndex');
15927 this.inputEl().focus();
15929 Roo.log('editor - hiding textarea');
15931 // Roo.log(this.pushValue());
15934 this.inputEl().addClass('hide');
15935 this.inputEl().dom.setAttribute('tabIndex', -1);
15936 //this.deferFocus();
15939 if(this.resizable){
15940 this.setSize(this.wrap.getSize());
15943 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
15946 // private (for BoxComponent)
15947 adjustSize : Roo.BoxComponent.prototype.adjustSize,
15949 // private (for BoxComponent)
15950 getResizeEl : function(){
15954 // private (for BoxComponent)
15955 getPositionEl : function(){
15960 initEvents : function(){
15961 this.originalValue = this.getValue();
15965 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
15968 // markInvalid : Roo.emptyFn,
15970 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
15973 // clearInvalid : Roo.emptyFn,
15975 setValue : function(v){
15976 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
15977 this.editorcore.pushValue();
15982 deferFocus : function(){
15983 this.focus.defer(10, this);
15987 focus : function(){
15988 this.editorcore.focus();
15994 onDestroy : function(){
16000 for (var i =0; i < this.toolbars.length;i++) {
16001 // fixme - ask toolbars for heights?
16002 this.toolbars[i].onDestroy();
16005 this.wrap.dom.innerHTML = '';
16006 this.wrap.remove();
16011 onFirstFocus : function(){
16012 //Roo.log("onFirstFocus");
16013 this.editorcore.onFirstFocus();
16014 for (var i =0; i < this.toolbars.length;i++) {
16015 this.toolbars[i].onFirstFocus();
16021 syncValue : function()
16023 this.editorcore.syncValue();
16026 pushValue : function()
16028 this.editorcore.pushValue();
16032 // hide stuff that is not compatible
16046 * @event specialkey
16050 * @cfg {String} fieldClass @hide
16053 * @cfg {String} focusClass @hide
16056 * @cfg {String} autoCreate @hide
16059 * @cfg {String} inputType @hide
16062 * @cfg {String} invalidClass @hide
16065 * @cfg {String} invalidText @hide
16068 * @cfg {String} msgFx @hide
16071 * @cfg {String} validateOnBlur @hide
16082 * @class Roo.bootstrap.HtmlEditorToolbar1
16087 new Roo.bootstrap.HtmlEditor({
16090 new Roo.bootstrap.HtmlEditorToolbar1({
16091 disable : { fonts: 1 , format: 1, ..., ... , ...],
16097 * @cfg {Object} disable List of elements to disable..
16098 * @cfg {Array} btns List of additional buttons.
16102 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
16105 Roo.bootstrap.HtmlEditor.ToolbarStandard = function(config)
16108 Roo.apply(this, config);
16110 // default disabled, based on 'good practice'..
16111 this.disable = this.disable || {};
16112 Roo.applyIf(this.disable, {
16115 specialElements : true
16117 Roo.bootstrap.HtmlEditor.ToolbarStandard.superclass.constructor.call(this, config);
16119 this.editor = config.editor;
16120 this.editorcore = config.editor.editorcore;
16122 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
16124 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
16125 // dont call parent... till later.
16127 Roo.extend(Roo.bootstrap.HtmlEditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
16133 editorcore : false,
16138 "h1","h2","h3","h4","h5","h6",
16140 "abbr", "acronym", "address", "cite", "samp", "var",
16144 onRender : function(ct, position)
16146 // Roo.log("Call onRender: " + this.xtype);
16148 Roo.bootstrap.HtmlEditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
16150 this.el.dom.style.marginBottom = '0';
16152 var editorcore = this.editorcore;
16153 var editor= this.editor;
16156 var btn = function(id,cmd , toggle, handler){
16158 var event = toggle ? 'toggle' : 'click';
16163 xns: Roo.bootstrap,
16166 enableToggle:toggle !== false,
16168 pressed : toggle ? false : null,
16171 a.listeners[toggle ? 'toggle' : 'click'] = function() {
16172 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
16181 xns: Roo.bootstrap,
16182 glyphicon : 'font',
16186 xns: Roo.bootstrap,
16190 Roo.each(this.formats, function(f) {
16191 style.menu.items.push({
16193 xns: Roo.bootstrap,
16194 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
16199 editorcore.insertTag(this.tagname);
16206 children.push(style);
16209 btn('bold',false,true);
16210 btn('italic',false,true);
16211 btn('align-left', 'justifyleft',true);
16212 btn('align-center', 'justifycenter',true);
16213 btn('align-right' , 'justifyright',true);
16214 btn('link', false, false, function(btn) {
16215 //Roo.log("create link?");
16216 var url = prompt(this.createLinkText, this.defaultLinkValue);
16217 if(url && url != 'http:/'+'/'){
16218 this.editorcore.relayCmd('createlink', url);
16221 btn('list','insertunorderedlist',true);
16222 btn('pencil', false,true, function(btn){
16225 this.toggleSourceEdit(btn.pressed);
16231 xns: Roo.bootstrap,
16236 xns: Roo.bootstrap,
16241 cog.menu.items.push({
16243 xns: Roo.bootstrap,
16244 html : Clean styles,
16249 editorcore.insertTag(this.tagname);
16258 this.xtype = 'NavSimplebar';
16260 for(var i=0;i< children.length;i++) {
16262 this.buttons.add(this.addxtypeChild(children[i]));
16266 editor.on('editorevent', this.updateToolbar, this);
16268 onBtnClick : function(id)
16270 this.editorcore.relayCmd(id);
16271 this.editorcore.focus();
16275 * Protected method that will not generally be called directly. It triggers
16276 * a toolbar update by reading the markup state of the current selection in the editor.
16278 updateToolbar: function(){
16280 if(!this.editorcore.activated){
16281 this.editor.onFirstFocus(); // is this neeed?
16285 var btns = this.buttons;
16286 var doc = this.editorcore.doc;
16287 btns.get('bold').setActive(doc.queryCommandState('bold'));
16288 btns.get('italic').setActive(doc.queryCommandState('italic'));
16289 //btns.get('underline').setActive(doc.queryCommandState('underline'));
16291 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
16292 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
16293 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
16295 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
16296 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
16299 var ans = this.editorcore.getAllAncestors();
16300 if (this.formatCombo) {
16303 var store = this.formatCombo.store;
16304 this.formatCombo.setValue("");
16305 for (var i =0; i < ans.length;i++) {
16306 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
16308 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
16316 // hides menus... - so this cant be on a menu...
16317 Roo.bootstrap.MenuMgr.hideAll();
16319 Roo.bootstrap.MenuMgr.hideAll();
16320 //this.editorsyncValue();
16322 onFirstFocus: function() {
16323 this.buttons.each(function(item){
16327 toggleSourceEdit : function(sourceEditMode){
16330 if(sourceEditMode){
16331 Roo.log("disabling buttons");
16332 this.buttons.each( function(item){
16333 if(item.cmd != 'pencil'){
16339 Roo.log("enabling buttons");
16340 if(this.editorcore.initialized){
16341 this.buttons.each( function(item){
16347 Roo.log("calling toggole on editor");
16348 // tell the editor that it's been pressed..
16349 this.editor.toggleSourceEdit(sourceEditMode);
16359 * @class Roo.bootstrap.Table.AbstractSelectionModel
16360 * @extends Roo.util.Observable
16361 * Abstract base class for grid SelectionModels. It provides the interface that should be
16362 * implemented by descendant classes. This class should not be directly instantiated.
16365 Roo.bootstrap.Table.AbstractSelectionModel = function(){
16366 this.locked = false;
16367 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
16371 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
16372 /** @ignore Called by the grid automatically. Do not call directly. */
16373 init : function(grid){
16379 * Locks the selections.
16382 this.locked = true;
16386 * Unlocks the selections.
16388 unlock : function(){
16389 this.locked = false;
16393 * Returns true if the selections are locked.
16394 * @return {Boolean}
16396 isLocked : function(){
16397 return this.locked;
16401 * @class Roo.bootstrap.Table.ColumnModel
16402 * @extends Roo.util.Observable
16403 * This is the default implementation of a ColumnModel used by the bootstrap table. It defines
16404 * the columns in the table.
16407 * @param {Object} config An Array of column config objects. See this class's
16408 * config objects for details.
16410 Roo.bootstrap.Table.ColumnModel = function(config){
16412 * The config passed into the constructor
16414 this.config = config;
16417 // if no id, create one
16418 // if the column does not have a dataIndex mapping,
16419 // map it to the order it is in the config
16420 for(var i = 0, len = config.length; i < len; i++){
16422 if(typeof c.dataIndex == "undefined"){
16425 if(typeof c.renderer == "string"){
16426 c.renderer = Roo.util.Format[c.renderer];
16428 if(typeof c.id == "undefined"){
16431 // if(c.editor && c.editor.xtype){
16432 // c.editor = Roo.factory(c.editor, Roo.grid);
16434 // if(c.editor && c.editor.isFormField){
16435 // c.editor = new Roo.grid.GridEditor(c.editor);
16438 this.lookup[c.id] = c;
16442 * The width of columns which have no width specified (defaults to 100)
16445 this.defaultWidth = 100;
16448 * Default sortable of columns which have no sortable specified (defaults to false)
16451 this.defaultSortable = false;
16455 * @event widthchange
16456 * Fires when the width of a column changes.
16457 * @param {ColumnModel} this
16458 * @param {Number} columnIndex The column index
16459 * @param {Number} newWidth The new width
16461 "widthchange": true,
16463 * @event headerchange
16464 * Fires when the text of a header changes.
16465 * @param {ColumnModel} this
16466 * @param {Number} columnIndex The column index
16467 * @param {Number} newText The new header text
16469 "headerchange": true,
16471 * @event hiddenchange
16472 * Fires when a column is hidden or "unhidden".
16473 * @param {ColumnModel} this
16474 * @param {Number} columnIndex The column index
16475 * @param {Boolean} hidden true if hidden, false otherwise
16477 "hiddenchange": true,
16479 * @event columnmoved
16480 * Fires when a column is moved.
16481 * @param {ColumnModel} this
16482 * @param {Number} oldIndex
16483 * @param {Number} newIndex
16485 "columnmoved" : true,
16487 * @event columlockchange
16488 * Fires when a column's locked state is changed
16489 * @param {ColumnModel} this
16490 * @param {Number} colIndex
16491 * @param {Boolean} locked true if locked
16493 "columnlockchange" : true
16495 Roo.bootstrap.Table.ColumnModel.superclass.constructor.call(this);
16497 Roo.extend(Roo.bootstrap.Table.ColumnModel, Roo.util.Observable, {
16499 * @cfg {String} header The header text to display in the Grid view.
16502 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
16503 * {@link Roo.data.Record} definition from which to draw the column's value. If not
16504 * specified, the column's index is used as an index into the Record's data Array.
16507 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
16508 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
16511 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
16512 * Defaults to the value of the {@link #defaultSortable} property.
16513 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
16516 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
16519 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
16522 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
16525 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
16528 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
16529 * given the cell's data value. See {@link #setRenderer}. If not specified, the
16530 * default renderer uses the raw data value.
16533 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
16537 * Returns the id of the column at the specified index.
16538 * @param {Number} index The column index
16539 * @return {String} the id
16541 getColumnId : function(index){
16542 return this.config[index].id;
16546 * Returns the column for a specified id.
16547 * @param {String} id The column id
16548 * @return {Object} the column
16550 getColumnById : function(id){
16551 return this.lookup[id];
16556 * Returns the column for a specified dataIndex.
16557 * @param {String} dataIndex The column dataIndex
16558 * @return {Object|Boolean} the column or false if not found
16560 getColumnByDataIndex: function(dataIndex){
16561 var index = this.findColumnIndex(dataIndex);
16562 return index > -1 ? this.config[index] : false;
16566 * Returns the index for a specified column id.
16567 * @param {String} id The column id
16568 * @return {Number} the index, or -1 if not found
16570 getIndexById : function(id){
16571 for(var i = 0, len = this.config.length; i < len; i++){
16572 if(this.config[i].id == id){
16580 * Returns the index for a specified column dataIndex.
16581 * @param {String} dataIndex The column dataIndex
16582 * @return {Number} the index, or -1 if not found
16585 findColumnIndex : function(dataIndex){
16586 for(var i = 0, len = this.config.length; i < len; i++){
16587 if(this.config[i].dataIndex == dataIndex){
16595 moveColumn : function(oldIndex, newIndex){
16596 var c = this.config[oldIndex];
16597 this.config.splice(oldIndex, 1);
16598 this.config.splice(newIndex, 0, c);
16599 this.dataMap = null;
16600 this.fireEvent("columnmoved", this, oldIndex, newIndex);
16603 isLocked : function(colIndex){
16604 return this.config[colIndex].locked === true;
16607 setLocked : function(colIndex, value, suppressEvent){
16608 if(this.isLocked(colIndex) == value){
16611 this.config[colIndex].locked = value;
16612 if(!suppressEvent){
16613 this.fireEvent("columnlockchange", this, colIndex, value);
16617 getTotalLockedWidth : function(){
16618 var totalWidth = 0;
16619 for(var i = 0; i < this.config.length; i++){
16620 if(this.isLocked(i) && !this.isHidden(i)){
16621 this.totalWidth += this.getColumnWidth(i);
16627 getLockedCount : function(){
16628 for(var i = 0, len = this.config.length; i < len; i++){
16629 if(!this.isLocked(i)){
16636 * Returns the number of columns.
16639 getColumnCount : function(visibleOnly){
16640 if(visibleOnly === true){
16642 for(var i = 0, len = this.config.length; i < len; i++){
16643 if(!this.isHidden(i)){
16649 return this.config.length;
16653 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
16654 * @param {Function} fn
16655 * @param {Object} scope (optional)
16656 * @return {Array} result
16658 getColumnsBy : function(fn, scope){
16660 for(var i = 0, len = this.config.length; i < len; i++){
16661 var c = this.config[i];
16662 if(fn.call(scope||this, c, i) === true){
16670 * Returns true if the specified column is sortable.
16671 * @param {Number} col The column index
16672 * @return {Boolean}
16674 isSortable : function(col){
16675 if(typeof this.config[col].sortable == "undefined"){
16676 return this.defaultSortable;
16678 return this.config[col].sortable;
16682 * Returns the rendering (formatting) function defined for the column.
16683 * @param {Number} col The column index.
16684 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
16686 getRenderer : function(col){
16687 if(!this.config[col].renderer){
16688 return Roo.bootstrap.Table.ColumnModel.defaultRenderer;
16690 return this.config[col].renderer;
16694 * Sets the rendering (formatting) function for a column.
16695 * @param {Number} col The column index
16696 * @param {Function} fn The function to use to process the cell's raw data
16697 * to return HTML markup for the grid view. The render function is called with
16698 * the following parameters:<ul>
16699 * <li>Data value.</li>
16700 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
16701 * <li>css A CSS style string to apply to the table cell.</li>
16702 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
16703 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
16704 * <li>Row index</li>
16705 * <li>Column index</li>
16706 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
16708 setRenderer : function(col, fn){
16709 this.config[col].renderer = fn;
16713 * Returns the width for the specified column.
16714 * @param {Number} col The column index
16717 getColumnWidth : function(col){
16718 return this.config[col].width * 1 || this.defaultWidth;
16722 * Sets the width for a column.
16723 * @param {Number} col The column index
16724 * @param {Number} width The new width
16726 setColumnWidth : function(col, width, suppressEvent){
16727 this.config[col].width = width;
16728 this.totalWidth = null;
16729 if(!suppressEvent){
16730 this.fireEvent("widthchange", this, col, width);
16735 * Returns the total width of all columns.
16736 * @param {Boolean} includeHidden True to include hidden column widths
16739 getTotalWidth : function(includeHidden){
16740 if(!this.totalWidth){
16741 this.totalWidth = 0;
16742 for(var i = 0, len = this.config.length; i < len; i++){
16743 if(includeHidden || !this.isHidden(i)){
16744 this.totalWidth += this.getColumnWidth(i);
16748 return this.totalWidth;
16752 * Returns the header for the specified column.
16753 * @param {Number} col The column index
16756 getColumnHeader : function(col){
16757 return this.config[col].header;
16761 * Sets the header for a column.
16762 * @param {Number} col The column index
16763 * @param {String} header The new header
16765 setColumnHeader : function(col, header){
16766 this.config[col].header = header;
16767 this.fireEvent("headerchange", this, col, header);
16771 * Returns the tooltip for the specified column.
16772 * @param {Number} col The column index
16775 getColumnTooltip : function(col){
16776 return this.config[col].tooltip;
16779 * Sets the tooltip for a column.
16780 * @param {Number} col The column index
16781 * @param {String} tooltip The new tooltip
16783 setColumnTooltip : function(col, tooltip){
16784 this.config[col].tooltip = tooltip;
16788 * Returns the dataIndex for the specified column.
16789 * @param {Number} col The column index
16792 getDataIndex : function(col){
16793 return this.config[col].dataIndex;
16797 * Sets the dataIndex for a column.
16798 * @param {Number} col The column index
16799 * @param {Number} dataIndex The new dataIndex
16801 setDataIndex : function(col, dataIndex){
16802 this.config[col].dataIndex = dataIndex;
16808 * Returns true if the cell is editable.
16809 * @param {Number} colIndex The column index
16810 * @param {Number} rowIndex The row index
16811 * @return {Boolean}
16813 isCellEditable : function(colIndex, rowIndex){
16814 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
16818 * Returns the editor defined for the cell/column.
16819 * return false or null to disable editing.
16820 * @param {Number} colIndex The column index
16821 * @param {Number} rowIndex The row index
16824 getCellEditor : function(colIndex, rowIndex){
16825 return this.config[colIndex].editor;
16829 * Sets if a column is editable.
16830 * @param {Number} col The column index
16831 * @param {Boolean} editable True if the column is editable
16833 setEditable : function(col, editable){
16834 this.config[col].editable = editable;
16839 * Returns true if the column is hidden.
16840 * @param {Number} colIndex The column index
16841 * @return {Boolean}
16843 isHidden : function(colIndex){
16844 return this.config[colIndex].hidden;
16849 * Returns true if the column width cannot be changed
16851 isFixed : function(colIndex){
16852 return this.config[colIndex].fixed;
16856 * Returns true if the column can be resized
16857 * @return {Boolean}
16859 isResizable : function(colIndex){
16860 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
16863 * Sets if a column is hidden.
16864 * @param {Number} colIndex The column index
16865 * @param {Boolean} hidden True if the column is hidden
16867 setHidden : function(colIndex, hidden){
16868 this.config[colIndex].hidden = hidden;
16869 this.totalWidth = null;
16870 this.fireEvent("hiddenchange", this, colIndex, hidden);
16874 * Sets the editor for a column.
16875 * @param {Number} col The column index
16876 * @param {Object} editor The editor object
16878 setEditor : function(col, editor){
16879 this.config[col].editor = editor;
16883 Roo.bootstrap.Table.ColumnModel.defaultRenderer = function(value){
16884 if(typeof value == "string" && value.length < 1){
16890 // Alias for backwards compatibility
16891 Roo.bootstrap.Table.DefaultColumnModel = Roo.bootstrap.Table.ColumnModel;
16894 * @extends Roo.bootstrap.Table.AbstractSelectionModel
16895 * @class Roo.bootstrap.Table.RowSelectionModel
16896 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
16897 * It supports multiple selections and keyboard selection/navigation.
16899 * @param {Object} config
16902 Roo.bootstrap.Table.RowSelectionModel = function(config){
16903 Roo.apply(this, config);
16904 this.selections = new Roo.util.MixedCollection(false, function(o){
16909 this.lastActive = false;
16913 * @event selectionchange
16914 * Fires when the selection changes
16915 * @param {SelectionModel} this
16917 "selectionchange" : true,
16919 * @event afterselectionchange
16920 * Fires after the selection changes (eg. by key press or clicking)
16921 * @param {SelectionModel} this
16923 "afterselectionchange" : true,
16925 * @event beforerowselect
16926 * Fires when a row is selected being selected, return false to cancel.
16927 * @param {SelectionModel} this
16928 * @param {Number} rowIndex The selected index
16929 * @param {Boolean} keepExisting False if other selections will be cleared
16931 "beforerowselect" : true,
16934 * Fires when a row is selected.
16935 * @param {SelectionModel} this
16936 * @param {Number} rowIndex The selected index
16937 * @param {Roo.data.Record} r The record
16939 "rowselect" : true,
16941 * @event rowdeselect
16942 * Fires when a row is deselected.
16943 * @param {SelectionModel} this
16944 * @param {Number} rowIndex The selected index
16946 "rowdeselect" : true
16948 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
16949 this.locked = false;
16952 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
16954 * @cfg {Boolean} singleSelect
16955 * True to allow selection of only one row at a time (defaults to false)
16957 singleSelect : false,
16960 initEvents : function(){
16962 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
16963 this.grid.on("mousedown", this.handleMouseDown, this);
16964 }else{ // allow click to work like normal
16965 this.grid.on("rowclick", this.handleDragableRowClick, this);
16968 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
16969 "up" : function(e){
16971 this.selectPrevious(e.shiftKey);
16972 }else if(this.last !== false && this.lastActive !== false){
16973 var last = this.last;
16974 this.selectRange(this.last, this.lastActive-1);
16975 this.grid.getView().focusRow(this.lastActive);
16976 if(last !== false){
16980 this.selectFirstRow();
16982 this.fireEvent("afterselectionchange", this);
16984 "down" : function(e){
16986 this.selectNext(e.shiftKey);
16987 }else if(this.last !== false && this.lastActive !== false){
16988 var last = this.last;
16989 this.selectRange(this.last, this.lastActive+1);
16990 this.grid.getView().focusRow(this.lastActive);
16991 if(last !== false){
16995 this.selectFirstRow();
16997 this.fireEvent("afterselectionchange", this);
17002 var view = this.grid.view;
17003 view.on("refresh", this.onRefresh, this);
17004 view.on("rowupdated", this.onRowUpdated, this);
17005 view.on("rowremoved", this.onRemove, this);
17009 onRefresh : function(){
17010 var ds = this.grid.dataSource, i, v = this.grid.view;
17011 var s = this.selections;
17012 s.each(function(r){
17013 if((i = ds.indexOfId(r.id)) != -1){
17022 onRemove : function(v, index, r){
17023 this.selections.remove(r);
17027 onRowUpdated : function(v, index, r){
17028 if(this.isSelected(r)){
17029 v.onRowSelect(index);
17035 * @param {Array} records The records to select
17036 * @param {Boolean} keepExisting (optional) True to keep existing selections
17038 selectRecords : function(records, keepExisting){
17040 this.clearSelections();
17042 var ds = this.grid.dataSource;
17043 for(var i = 0, len = records.length; i < len; i++){
17044 this.selectRow(ds.indexOf(records[i]), true);
17049 * Gets the number of selected rows.
17052 getCount : function(){
17053 return this.selections.length;
17057 * Selects the first row in the grid.
17059 selectFirstRow : function(){
17064 * Select the last row.
17065 * @param {Boolean} keepExisting (optional) True to keep existing selections
17067 selectLastRow : function(keepExisting){
17068 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
17072 * Selects the row immediately following the last selected row.
17073 * @param {Boolean} keepExisting (optional) True to keep existing selections
17075 selectNext : function(keepExisting){
17076 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
17077 this.selectRow(this.last+1, keepExisting);
17078 this.grid.getView().focusRow(this.last);
17083 * Selects the row that precedes the last selected row.
17084 * @param {Boolean} keepExisting (optional) True to keep existing selections
17086 selectPrevious : function(keepExisting){
17088 this.selectRow(this.last-1, keepExisting);
17089 this.grid.getView().focusRow(this.last);
17094 * Returns the selected records
17095 * @return {Array} Array of selected records
17097 getSelections : function(){
17098 return [].concat(this.selections.items);
17102 * Returns the first selected record.
17105 getSelected : function(){
17106 return this.selections.itemAt(0);
17111 * Clears all selections.
17113 clearSelections : function(fast){
17114 if(this.locked) return;
17116 var ds = this.grid.dataSource;
17117 var s = this.selections;
17118 s.each(function(r){
17119 this.deselectRow(ds.indexOfId(r.id));
17123 this.selections.clear();
17130 * Selects all rows.
17132 selectAll : function(){
17133 if(this.locked) return;
17134 this.selections.clear();
17135 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
17136 this.selectRow(i, true);
17141 * Returns True if there is a selection.
17142 * @return {Boolean}
17144 hasSelection : function(){
17145 return this.selections.length > 0;
17149 * Returns True if the specified row is selected.
17150 * @param {Number/Record} record The record or index of the record to check
17151 * @return {Boolean}
17153 isSelected : function(index){
17154 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
17155 return (r && this.selections.key(r.id) ? true : false);
17159 * Returns True if the specified record id is selected.
17160 * @param {String} id The id of record to check
17161 * @return {Boolean}
17163 isIdSelected : function(id){
17164 return (this.selections.key(id) ? true : false);
17168 handleMouseDown : function(e, t){
17169 var view = this.grid.getView(), rowIndex;
17170 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
17173 if(e.shiftKey && this.last !== false){
17174 var last = this.last;
17175 this.selectRange(last, rowIndex, e.ctrlKey);
17176 this.last = last; // reset the last
17177 view.focusRow(rowIndex);
17179 var isSelected = this.isSelected(rowIndex);
17180 if(e.button !== 0 && isSelected){
17181 view.focusRow(rowIndex);
17182 }else if(e.ctrlKey && isSelected){
17183 this.deselectRow(rowIndex);
17184 }else if(!isSelected){
17185 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
17186 view.focusRow(rowIndex);
17189 this.fireEvent("afterselectionchange", this);
17192 handleDragableRowClick : function(grid, rowIndex, e)
17194 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
17195 this.selectRow(rowIndex, false);
17196 grid.view.focusRow(rowIndex);
17197 this.fireEvent("afterselectionchange", this);
17202 * Selects multiple rows.
17203 * @param {Array} rows Array of the indexes of the row to select
17204 * @param {Boolean} keepExisting (optional) True to keep existing selections
17206 selectRows : function(rows, keepExisting){
17208 this.clearSelections();
17210 for(var i = 0, len = rows.length; i < len; i++){
17211 this.selectRow(rows[i], true);
17216 * Selects a range of rows. All rows in between startRow and endRow are also selected.
17217 * @param {Number} startRow The index of the first row in the range
17218 * @param {Number} endRow The index of the last row in the range
17219 * @param {Boolean} keepExisting (optional) True to retain existing selections
17221 selectRange : function(startRow, endRow, keepExisting){
17222 if(this.locked) return;
17224 this.clearSelections();
17226 if(startRow <= endRow){
17227 for(var i = startRow; i <= endRow; i++){
17228 this.selectRow(i, true);
17231 for(var i = startRow; i >= endRow; i--){
17232 this.selectRow(i, true);
17238 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
17239 * @param {Number} startRow The index of the first row in the range
17240 * @param {Number} endRow The index of the last row in the range
17242 deselectRange : function(startRow, endRow, preventViewNotify){
17243 if(this.locked) return;
17244 for(var i = startRow; i <= endRow; i++){
17245 this.deselectRow(i, preventViewNotify);
17251 * @param {Number} row The index of the row to select
17252 * @param {Boolean} keepExisting (optional) True to keep existing selections
17254 selectRow : function(index, keepExisting, preventViewNotify){
17255 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
17256 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
17257 if(!keepExisting || this.singleSelect){
17258 this.clearSelections();
17260 var r = this.grid.dataSource.getAt(index);
17261 this.selections.add(r);
17262 this.last = this.lastActive = index;
17263 if(!preventViewNotify){
17264 this.grid.getView().onRowSelect(index);
17266 this.fireEvent("rowselect", this, index, r);
17267 this.fireEvent("selectionchange", this);
17273 * @param {Number} row The index of the row to deselect
17275 deselectRow : function(index, preventViewNotify){
17276 if(this.locked) return;
17277 if(this.last == index){
17280 if(this.lastActive == index){
17281 this.lastActive = false;
17283 var r = this.grid.dataSource.getAt(index);
17284 this.selections.remove(r);
17285 if(!preventViewNotify){
17286 this.grid.getView().onRowDeselect(index);
17288 this.fireEvent("rowdeselect", this, index);
17289 this.fireEvent("selectionchange", this);
17293 restoreLast : function(){
17295 this.last = this._last;
17300 acceptsNav : function(row, col, cm){
17301 return !cm.isHidden(col) && cm.isCellEditable(col, row);
17305 onEditorKey : function(field, e){
17306 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
17311 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
17313 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
17315 }else if(k == e.ENTER && !e.ctrlKey){
17319 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
17321 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
17323 }else if(k == e.ESC){
17327 g.startEditing(newCell[0], newCell[1]);
17338 * @class Roo.bootstrap.MessageBar
17339 * @extends Roo.bootstrap.Component
17340 * Bootstrap MessageBar class
17341 * @cfg {String} html contents of the MessageBar
17342 * @cfg {String} weight (info | success | warning | danger) default info
17343 * @cfg {String} beforeClass insert the bar before the given class
17344 * @cfg {Boolean} closable (true | false) default false
17345 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
17348 * Create a new Element
17349 * @param {Object} config The config object
17352 Roo.bootstrap.MessageBar = function(config){
17353 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
17356 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
17362 beforeClass: 'bootstrap-sticky-wrap',
17364 getAutoCreate : function(){
17368 cls: 'alert alert-dismissable alert-' + this.weight,
17373 html: this.html || ''
17379 cfg.cls += ' alert-messages-fixed';
17393 onRender : function(ct, position)
17395 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17398 var cfg = Roo.apply({}, this.getAutoCreate());
17402 cfg.cls += ' ' + this.cls;
17405 cfg.style = this.style;
17407 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
17409 this.el.setVisibilityMode(Roo.Element.DISPLAY);
17412 this.el.select('>button.close').on('click', this.hide, this);
17418 if (!this.rendered) {
17424 this.fireEvent('show', this);
17430 if (!this.rendered) {
17436 this.fireEvent('hide', this);
17439 update : function()
17441 // var e = this.el.dom.firstChild;
17443 // if(this.closable){
17444 // e = e.nextSibling;
17447 // e.data = this.html || '';
17449 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';