4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
21 * Do not use directly - it does not do anything..
22 * @param {Object} config The config object
27 Roo.bootstrap.Component = function(config){
28 Roo.bootstrap.Component.superclass.constructor.call(this, config);
31 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
34 allowDomMove : false, // to stop relocations in parent onRender...
42 initEvents : function() { },
48 can_build_overlaid : true,
55 // returns the parent component..
56 return Roo.ComponentMgr.get(this.parentId)
62 onRender : function(ct, position)
64 // Roo.log("Call onRender: " + this.xtype);
66 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
69 if (this.el.attr('xtype')) {
70 this.el.attr('xtypex', this.el.attr('xtype'));
71 this.el.dom.removeAttribute('xtype');
81 var cfg = Roo.apply({}, this.getAutoCreate());
84 // fill in the extra attributes
85 if (this.xattr && typeof(this.xattr) =='object') {
86 for (var i in this.xattr) {
87 cfg[i] = this.xattr[i];
92 cfg.dataId = this.dataId;
96 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
99 if (this.style) { // fixme needs to support more complex style data.
100 cfg.style = this.style;
104 cfg.name = this.name;
107 this.el = ct.createChild(cfg, position);
109 if(this.tabIndex !== undefined){
110 this.el.dom.setAttribute('tabIndex', this.tabIndex);
117 getChildContainer : function()
123 addxtype : function(tree,cntr)
127 cn = Roo.factory(tree);
129 cn.parentType = this.xtype; //??
130 cn.parentId = this.id;
132 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
134 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
136 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
138 var build_from_html = Roo.XComponent.build_from_html;
140 var is_body = (tree.xtype == 'Body') ;
142 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
144 var self_cntr_el = Roo.get(this[cntr](false));
146 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
147 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
148 return this.addxtypeChild(tree,cntr);
151 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
154 return this.addxtypeChild(Roo.apply({}, tree),cntr);
157 Roo.log('skipping render');
165 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
171 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
175 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
180 addxtypeChild : function (tree, cntr)
182 Roo.log('addxtypeChild:' + cntr);
184 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
187 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
188 (typeof(tree['flexy:foreach']) != 'undefined');
193 // render the element if it's not BODY.
194 if (tree.xtype != 'Body') {
196 cn = Roo.factory(tree);
198 cn.parentType = this.xtype; //??
199 cn.parentId = this.id;
201 var build_from_html = Roo.XComponent.build_from_html;
204 // does the container contain child eleemnts with 'xtype' attributes.
205 // that match this xtype..
206 // note - when we render we create these as well..
207 // so we should check to see if body has xtype set.
208 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
210 var self_cntr_el = Roo.get(this[cntr](false));
211 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
213 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
214 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
220 //echild.dom.removeAttribute('xtype');
222 Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
229 // if object has flexy:if - then it may or may not be rendered.
230 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
231 // skip a flexy if element.
232 Roo.log('skipping render');
235 // actually if flexy:foreach is found, we really want to create
236 // multiple copies here...
238 //Roo.log(this[cntr]());
239 cn.render(this[cntr](true));
241 // then add the element..
249 if (typeof (tree.menu) != 'undefined') {
250 tree.menu.parentType = cn.xtype;
251 tree.menu.triggerEl = cn.el;
252 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
256 if (!tree.items || !tree.items.length) {
260 var items = tree.items;
263 //Roo.log(items.length);
265 for(var i =0;i < items.length;i++) {
266 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
287 * @class Roo.bootstrap.Body
288 * @extends Roo.bootstrap.Component
289 * Bootstrap Body class
293 * @param {Object} config The config object
296 Roo.bootstrap.Body = function(config){
297 Roo.bootstrap.Body.superclass.constructor.call(this, config);
298 this.el = Roo.get(document.body);
299 if (this.cls && this.cls.length) {
300 Roo.get(document.body).addClass(this.cls);
304 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
309 onRender : function(ct, position)
311 /* Roo.log("Roo.bootstrap.Body - onRender");
312 if (this.cls && this.cls.length) {
313 Roo.get(document.body).addClass(this.cls);
333 * @class Roo.bootstrap.ButtonGroup
334 * @extends Roo.bootstrap.Component
335 * Bootstrap ButtonGroup class
336 * @cfg {String} size lg | sm | xs (default empty normal)
337 * @cfg {String} align vertical | justified (default none)
338 * @cfg {String} direction up | down (default down)
339 * @cfg {Boolean} toolbar false | true
340 * @cfg {Boolean} btn true | false
345 * @param {Object} config The config object
348 Roo.bootstrap.ButtonGroup = function(config){
349 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
352 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
360 getAutoCreate : function(){
366 cfg.html = this.html || cfg.html;
377 if (['vertical','justified'].indexOf(this.align)!==-1) {
378 cfg.cls = 'btn-group-' + this.align;
380 if (this.align == 'justified') {
381 console.log(this.items);
385 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
386 cfg.cls += ' btn-group-' + this.size;
389 if (this.direction == 'up') {
390 cfg.cls += ' dropup' ;
406 * @class Roo.bootstrap.Button
407 * @extends Roo.bootstrap.Component
408 * Bootstrap Button class
409 * @cfg {String} html The button content
410 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger | link
411 * @cfg {String} size empty | lg | sm | xs
412 * @cfg {String} tag empty | a | input | submit
413 * @cfg {String} href empty or href
414 * @cfg {Boolean} disabled false | true
415 * @cfg {Boolean} isClose false | true
416 * @cfg {String} glyphicon empty | adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out
417 * @cfg {String} badge text for badge
418 * @cfg {String} theme default (or empty) | glow
419 * @cfg {Boolean} inverse false | true
420 * @cfg {Boolean} toggle false | true
421 * @cfg {String} ontext text for on toggle state
422 * @cfg {String} offtext text for off toggle state
423 * @cfg {Boolean} defaulton true | false
424 * @cfg {Boolean} preventDefault (true | false) default true
425 * @cfg {Boolean} removeClass true | false remove the standard class..
426 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
429 * Create a new button
430 * @param {Object} config The config object
434 Roo.bootstrap.Button = function(config){
435 Roo.bootstrap.Button.superclass.constructor.call(this, config);
440 * When a butotn is pressed
441 * @param {Roo.EventObject} e
446 * After the button has been toggles
447 * @param {Roo.EventObject} e
448 * @param {boolean} pressed (also available as button.pressed)
454 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
472 preventDefault: true,
481 getAutoCreate : function(){
489 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
490 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
495 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
497 if (this.toggle == true) {
500 cls: 'slider-frame roo-button',
505 'data-off-text':'OFF',
506 cls: 'slider-button',
512 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
513 cfg.cls += ' '+this.weight;
522 cfg["aria-hidden"] = true;
524 cfg.html = "×";
530 if (this.theme==='default') {
531 cfg.cls = 'btn roo-button';
533 //if (this.parentType != 'Navbar') {
534 this.weight = this.weight.length ? this.weight : 'default';
536 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
538 cfg.cls += ' btn-' + this.weight;
540 } else if (this.theme==='glow') {
543 cfg.cls = 'btn-glow roo-button';
545 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
547 cfg.cls += ' ' + this.weight;
553 this.cls += ' inverse';
558 cfg.cls += ' active';
562 cfg.disabled = 'disabled';
566 Roo.log('changing to ul' );
568 this.glyphicon = 'caret';
571 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
573 //gsRoo.log(this.parentType);
574 if (this.parentType === 'Navbar' && !this.parent().bar) {
575 Roo.log('changing to li?');
584 href : this.href || '#'
587 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
588 cfg.cls += ' dropdown';
595 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
597 if (this.glyphicon) {
598 cfg.html = ' ' + cfg.html;
603 cls: 'glyphicon glyphicon-' + this.glyphicon
613 // cfg.cls='btn roo-button';
617 var value = cfg.html;
622 cls: 'glyphicon glyphicon-' + this.glyphicon,
641 cfg.cls += ' dropdown';
642 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
645 if (cfg.tag !== 'a' && this.href !== '') {
646 throw "Tag must be a to set href.";
647 } else if (this.href.length > 0) {
648 cfg.href = this.href;
651 if(this.removeClass){
656 cfg.target = this.target;
661 initEvents: function() {
662 // Roo.log('init events?');
663 // Roo.log(this.el.dom);
666 if (typeof (this.menu) != 'undefined') {
667 this.menu.parentType = this.xtype;
668 this.menu.triggerEl = this.el;
669 this.addxtype(Roo.apply({}, this.menu));
673 if (this.el.hasClass('roo-button')) {
674 this.el.on('click', this.onClick, this);
676 this.el.select('.roo-button').on('click', this.onClick, this);
679 if(this.removeClass){
680 this.el.on('click', this.onClick, this);
683 this.el.enableDisplayMode();
686 onClick : function(e)
692 Roo.log('button on click ');
693 if(this.preventDefault){
696 if (this.pressed === true || this.pressed === false) {
697 this.pressed = !this.pressed;
698 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
699 this.fireEvent('toggle', this, e, this.pressed);
703 this.fireEvent('click', this, e);
707 * Enables this button
711 this.disabled = false;
712 this.el.removeClass('disabled');
716 * Disable this button
720 this.disabled = true;
721 this.el.addClass('disabled');
724 * sets the active state on/off,
725 * @param {Boolean} state (optional) Force a particular state
727 setActive : function(v) {
729 this.el[v ? 'addClass' : 'removeClass']('active');
732 * toggles the current active state
734 toggleActive : function()
736 var active = this.el.hasClass('active');
737 this.setActive(!active);
741 setText : function(str)
743 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
747 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
770 * @class Roo.bootstrap.Column
771 * @extends Roo.bootstrap.Component
772 * Bootstrap Column class
773 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
774 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
775 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
776 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
777 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
778 * @cfg {String} fa (ban|check|...) font awesome icon
779 * @cfg {String} icon (info-sign|check|...) glyphicon name
781 * @cfg {String} html content of column.
784 * Create a new Column
785 * @param {Object} config The config object
788 Roo.bootstrap.Column = function(config){
789 Roo.bootstrap.Column.superclass.constructor.call(this, config);
792 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
804 getAutoCreate : function(){
805 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
813 ['xs','sm','md','lg'].map(function(size){
814 Roo.log( size + ':' + settings[size]);
815 if (settings[size] === false) {
818 Roo.log(settings[size]);
819 if (!settings[size]) { // 0 = hidden
820 cfg.cls += ' hidden-' + size;
823 cfg.cls += ' col-' + size + '-' + settings[size];
827 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
828 cfg.cls +=' alert alert-' + this.alert;
832 if (this.html.length) {
833 cfg.html = this.html;
836 cfg.html = '<i class="fa fa-'+this.fa + '"></i>' + (cfg.html || '');
839 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + + (cfg.html || '')
858 * @class Roo.bootstrap.Container
859 * @extends Roo.bootstrap.Component
860 * Bootstrap Container class
861 * @cfg {Boolean} jumbotron is it a jumbotron element
862 * @cfg {String} html content of element
863 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
864 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
865 * @cfg {String} header content of header (for panel)
866 * @cfg {String} footer content of footer (for panel)
867 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
868 * @cfg {String} tag (header|aside|section) type of HTML tag.
869 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
870 * @cfg {String} fa (ban|check|...) font awesome icon
871 * @cfg {String} icon (info-sign|check|...) glyphicon name
875 * Create a new Container
876 * @param {Object} config The config object
879 Roo.bootstrap.Container = function(config){
880 Roo.bootstrap.Container.superclass.constructor.call(this, config);
883 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
897 getChildContainer : function() {
903 if (this.panel.length) {
904 return this.el.select('.panel-body',true).first();
911 getAutoCreate : function(){
914 tag : this.tag || 'div',
918 if (this.jumbotron) {
919 cfg.cls = 'jumbotron';
924 // - this is applied by the parent..
926 // cfg.cls = this.cls + '';
929 if (this.sticky.length) {
931 var bd = Roo.get(document.body);
932 if (!bd.hasClass('bootstrap-sticky')) {
933 bd.addClass('bootstrap-sticky');
934 Roo.select('html',true).setStyle('height', '100%');
937 cfg.cls += 'bootstrap-sticky-' + this.sticky;
941 if (this.well.length) {
945 cfg.cls +=' well well-' +this.well;
952 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
953 cfg.cls +=' alert alert-' + this.alert;
958 if (this.panel.length) {
959 cfg.cls += ' panel panel-' + this.panel;
961 if (this.header.length) {
964 cls : 'panel-heading',
980 if (this.footer.length) {
982 cls : 'panel-footer',
991 body.html = this.html || cfg.html;
992 // prefix with the icons..
994 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
997 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1002 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1003 cfg.cls = 'container';
1009 titleEl : function()
1011 if(!this.el || !this.panel.length || !this.header.length){
1015 return this.el.select('.panel-title',true).first();
1018 setTitle : function(v)
1020 var titleEl = this.titleEl();
1026 titleEl.dom.innerHTML = v;
1029 getTitle : function()
1032 var titleEl = this.titleEl();
1038 return titleEl.dom.innerHTML;
1052 * @class Roo.bootstrap.Img
1053 * @extends Roo.bootstrap.Component
1054 * Bootstrap Img class
1055 * @cfg {Boolean} imgResponsive false | true
1056 * @cfg {String} border rounded | circle | thumbnail
1057 * @cfg {String} src image source
1058 * @cfg {String} alt image alternative text
1059 * @cfg {String} href a tag href
1060 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1063 * Create a new Input
1064 * @param {Object} config The config object
1067 Roo.bootstrap.Img = function(config){
1068 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1074 * The img click event for the img.
1075 * @param {Roo.EventObject} e
1081 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1083 imgResponsive: true,
1089 getAutoCreate : function(){
1093 cls: (this.imgResponsive) ? 'img-responsive' : '',
1097 cfg.html = this.html || cfg.html;
1099 cfg.src = this.src || cfg.src;
1101 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1102 cfg.cls += ' img-' + this.border;
1119 a.target = this.target;
1125 return (this.href) ? a : cfg;
1128 initEvents: function() {
1131 this.el.on('click', this.onClick, this);
1135 onClick : function(e)
1137 Roo.log('img onclick');
1138 this.fireEvent('click', this, e);
1152 * @class Roo.bootstrap.Link
1153 * @extends Roo.bootstrap.Component
1154 * Bootstrap Link Class
1155 * @cfg {String} alt image alternative text
1156 * @cfg {String} href a tag href
1157 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1158 * @cfg {String} html the content of the link.
1159 * @cfg {Boolean} preventDefault (true | false) default false
1163 * Create a new Input
1164 * @param {Object} config The config object
1167 Roo.bootstrap.Link = function(config){
1168 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1174 * The img click event for the img.
1175 * @param {Roo.EventObject} e
1181 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1185 preventDefault: false,
1187 getAutoCreate : function(){
1191 html : this.html || 'html-missing'
1198 cfg.href = this.href || '#';
1200 cfg.target = this.target;
1206 initEvents: function() {
1208 if(!this.href || this.preventDefault){
1209 this.el.on('click', this.onClick, this);
1213 onClick : function(e)
1215 if(this.preventDefault){
1218 //Roo.log('img onclick');
1219 this.fireEvent('click', this, e);
1232 * @class Roo.bootstrap.Header
1233 * @extends Roo.bootstrap.Component
1234 * Bootstrap Header class
1235 * @cfg {String} html content of header
1236 * @cfg {Number} level (1|2|3|4|5|6) default 1
1239 * Create a new Header
1240 * @param {Object} config The config object
1244 Roo.bootstrap.Header = function(config){
1245 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1248 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1256 getAutoCreate : function(){
1259 tag: 'h' + (1 *this.level),
1260 html: this.html || 'fill in html'
1272 * Ext JS Library 1.1.1
1273 * Copyright(c) 2006-2007, Ext JS, LLC.
1275 * Originally Released Under LGPL - original licence link has changed is not relivant.
1278 * <script type="text/javascript">
1282 * @class Roo.bootstrap.MenuMgr
1283 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1286 Roo.bootstrap.MenuMgr = function(){
1287 var menus, active, groups = {}, attached = false, lastShow = new Date();
1289 // private - called when first menu is created
1292 active = new Roo.util.MixedCollection();
1293 Roo.get(document).addKeyListener(27, function(){
1294 if(active.length > 0){
1302 if(active && active.length > 0){
1303 var c = active.clone();
1313 if(active.length < 1){
1314 Roo.get(document).un("mouseup", onMouseDown);
1322 var last = active.last();
1323 lastShow = new Date();
1326 Roo.get(document).on("mouseup", onMouseDown);
1331 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1332 m.parentMenu.activeChild = m;
1333 }else if(last && last.isVisible()){
1334 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1339 function onBeforeHide(m){
1341 m.activeChild.hide();
1343 if(m.autoHideTimer){
1344 clearTimeout(m.autoHideTimer);
1345 delete m.autoHideTimer;
1350 function onBeforeShow(m){
1351 var pm = m.parentMenu;
1352 if(!pm && !m.allowOtherMenus){
1354 }else if(pm && pm.activeChild && active != m){
1355 pm.activeChild.hide();
1360 function onMouseDown(e){
1361 Roo.log("on MouseDown");
1362 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1370 function onBeforeCheck(mi, state){
1372 var g = groups[mi.group];
1373 for(var i = 0, l = g.length; i < l; i++){
1375 g[i].setChecked(false);
1384 * Hides all menus that are currently visible
1386 hideAll : function(){
1391 register : function(menu){
1395 menus[menu.id] = menu;
1396 menu.on("beforehide", onBeforeHide);
1397 menu.on("hide", onHide);
1398 menu.on("beforeshow", onBeforeShow);
1399 menu.on("show", onShow);
1401 if(g && menu.events["checkchange"]){
1405 groups[g].push(menu);
1406 menu.on("checkchange", onCheck);
1411 * Returns a {@link Roo.menu.Menu} object
1412 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1413 * be used to generate and return a new Menu instance.
1415 get : function(menu){
1416 if(typeof menu == "string"){ // menu id
1418 }else if(menu.events){ // menu instance
1421 /*else if(typeof menu.length == 'number'){ // array of menu items?
1422 return new Roo.bootstrap.Menu({items:menu});
1423 }else{ // otherwise, must be a config
1424 return new Roo.bootstrap.Menu(menu);
1431 unregister : function(menu){
1432 delete menus[menu.id];
1433 menu.un("beforehide", onBeforeHide);
1434 menu.un("hide", onHide);
1435 menu.un("beforeshow", onBeforeShow);
1436 menu.un("show", onShow);
1438 if(g && menu.events["checkchange"]){
1439 groups[g].remove(menu);
1440 menu.un("checkchange", onCheck);
1445 registerCheckable : function(menuItem){
1446 var g = menuItem.group;
1451 groups[g].push(menuItem);
1452 menuItem.on("beforecheckchange", onBeforeCheck);
1457 unregisterCheckable : function(menuItem){
1458 var g = menuItem.group;
1460 groups[g].remove(menuItem);
1461 menuItem.un("beforecheckchange", onBeforeCheck);
1473 * @class Roo.bootstrap.Menu
1474 * @extends Roo.bootstrap.Component
1475 * Bootstrap Menu class - container for MenuItems
1476 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1480 * @param {Object} config The config object
1484 Roo.bootstrap.Menu = function(config){
1485 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1486 if (this.registerMenu) {
1487 Roo.bootstrap.MenuMgr.register(this);
1492 * Fires before this menu is displayed
1493 * @param {Roo.menu.Menu} this
1498 * Fires before this menu is hidden
1499 * @param {Roo.menu.Menu} this
1504 * Fires after this menu is displayed
1505 * @param {Roo.menu.Menu} this
1510 * Fires after this menu is hidden
1511 * @param {Roo.menu.Menu} this
1516 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1517 * @param {Roo.menu.Menu} this
1518 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1519 * @param {Roo.EventObject} e
1524 * Fires when the mouse is hovering over this menu
1525 * @param {Roo.menu.Menu} this
1526 * @param {Roo.EventObject} e
1527 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1532 * Fires when the mouse exits this menu
1533 * @param {Roo.menu.Menu} this
1534 * @param {Roo.EventObject} e
1535 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1540 * Fires when a menu item contained in this menu is clicked
1541 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1542 * @param {Roo.EventObject} e
1546 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1549 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1553 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1556 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1558 registerMenu : true,
1560 menuItems :false, // stores the menu items..
1566 getChildContainer : function() {
1570 getAutoCreate : function(){
1572 //if (['right'].indexOf(this.align)!==-1) {
1573 // cfg.cn[1].cls += ' pull-right'
1579 cls : 'dropdown-menu' ,
1580 style : 'z-index:1000'
1584 if (this.type === 'submenu') {
1585 cfg.cls = 'submenu active';
1587 if (this.type === 'treeview') {
1588 cfg.cls = 'treeview-menu';
1593 initEvents : function() {
1595 // Roo.log("ADD event");
1596 // Roo.log(this.triggerEl.dom);
1597 this.triggerEl.on('click', this.onTriggerPress, this);
1598 this.triggerEl.addClass('dropdown-toggle');
1599 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1601 this.el.on("mouseover", this.onMouseOver, this);
1602 this.el.on("mouseout", this.onMouseOut, this);
1606 findTargetItem : function(e){
1607 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1611 //Roo.log(t); Roo.log(t.id);
1613 //Roo.log(this.menuitems);
1614 return this.menuitems.get(t.id);
1616 //return this.items.get(t.menuItemId);
1621 onClick : function(e){
1622 Roo.log("menu.onClick");
1623 var t = this.findTargetItem(e);
1629 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1630 if(t == this.activeItem && t.shouldDeactivate(e)){
1631 this.activeItem.deactivate();
1632 delete this.activeItem;
1636 this.setActiveItem(t, true);
1643 Roo.log('pass click event');
1647 this.fireEvent("click", this, t, e);
1651 onMouseOver : function(e){
1652 var t = this.findTargetItem(e);
1655 // if(t.canActivate && !t.disabled){
1656 // this.setActiveItem(t, true);
1660 this.fireEvent("mouseover", this, e, t);
1662 isVisible : function(){
1663 return !this.hidden;
1665 onMouseOut : function(e){
1666 var t = this.findTargetItem(e);
1669 // if(t == this.activeItem && t.shouldDeactivate(e)){
1670 // this.activeItem.deactivate();
1671 // delete this.activeItem;
1674 this.fireEvent("mouseout", this, e, t);
1679 * Displays this menu relative to another element
1680 * @param {String/HTMLElement/Roo.Element} element The element to align to
1681 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1682 * the element (defaults to this.defaultAlign)
1683 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1685 show : function(el, pos, parentMenu){
1686 this.parentMenu = parentMenu;
1690 this.fireEvent("beforeshow", this);
1691 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1694 * Displays this menu at a specific xy position
1695 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1696 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1698 showAt : function(xy, parentMenu, /* private: */_e){
1699 this.parentMenu = parentMenu;
1704 this.fireEvent("beforeshow", this);
1706 //xy = this.el.adjustForConstraints(xy);
1708 //this.el.setXY(xy);
1710 this.hideMenuItems();
1711 this.hidden = false;
1712 this.triggerEl.addClass('open');
1714 this.fireEvent("show", this);
1720 this.doFocus.defer(50, this);
1724 doFocus : function(){
1726 this.focusEl.focus();
1731 * Hides this menu and optionally all parent menus
1732 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1734 hide : function(deep){
1736 this.hideMenuItems();
1737 if(this.el && this.isVisible()){
1738 this.fireEvent("beforehide", this);
1739 if(this.activeItem){
1740 this.activeItem.deactivate();
1741 this.activeItem = null;
1743 this.triggerEl.removeClass('open');;
1745 this.fireEvent("hide", this);
1747 if(deep === true && this.parentMenu){
1748 this.parentMenu.hide(true);
1752 onTriggerPress : function(e)
1755 Roo.log('trigger press');
1756 //Roo.log(e.getTarget());
1757 // Roo.log(this.triggerEl.dom);
1758 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1761 if (this.isVisible()) {
1765 this.show(this.triggerEl, false, false);
1774 hideMenuItems : function()
1776 //$(backdrop).remove()
1777 Roo.select('.open',true).each(function(aa) {
1779 aa.removeClass('open');
1780 //var parent = getParent($(this))
1781 //var relatedTarget = { relatedTarget: this }
1783 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1784 //if (e.isDefaultPrevented()) return
1785 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1788 addxtypeChild : function (tree, cntr) {
1789 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1791 this.menuitems.add(comp);
1812 * @class Roo.bootstrap.MenuItem
1813 * @extends Roo.bootstrap.Component
1814 * Bootstrap MenuItem class
1815 * @cfg {String} html the menu label
1816 * @cfg {String} href the link
1817 * @cfg {Boolean} preventDefault (true | false) default true
1821 * Create a new MenuItem
1822 * @param {Object} config The config object
1826 Roo.bootstrap.MenuItem = function(config){
1827 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1832 * The raw click event for the entire grid.
1833 * @param {Roo.EventObject} e
1839 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1843 preventDefault: true,
1845 getAutoCreate : function(){
1848 cls: 'dropdown-menu-item',
1857 if (this.parent().type == 'treeview') {
1858 cfg.cls = 'treeview-menu';
1861 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1862 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1866 initEvents: function() {
1868 //this.el.select('a').on('click', this.onClick, this);
1871 onClick : function(e)
1873 Roo.log('item on click ');
1874 //if(this.preventDefault){
1875 // e.preventDefault();
1877 //this.parent().hideMenuItems();
1879 this.fireEvent('click', this, e);
1898 * @class Roo.bootstrap.MenuSeparator
1899 * @extends Roo.bootstrap.Component
1900 * Bootstrap MenuSeparator class
1903 * Create a new MenuItem
1904 * @param {Object} config The config object
1908 Roo.bootstrap.MenuSeparator = function(config){
1909 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1912 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1914 getAutoCreate : function(){
1929 <div class="modal fade">
1930 <div class="modal-dialog">
1931 <div class="modal-content">
1932 <div class="modal-header">
1933 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1934 <h4 class="modal-title">Modal title</h4>
1936 <div class="modal-body">
1937 <p>One fine body…</p>
1939 <div class="modal-footer">
1940 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1941 <button type="button" class="btn btn-primary">Save changes</button>
1943 </div><!-- /.modal-content -->
1944 </div><!-- /.modal-dialog -->
1945 </div><!-- /.modal -->
1955 * @class Roo.bootstrap.Modal
1956 * @extends Roo.bootstrap.Component
1957 * Bootstrap Modal class
1958 * @cfg {String} title Title of dialog
1959 * @cfg {Boolean} specificTitle (true|false) default false
1960 * @cfg {Array} buttons Array of buttons or standard button set..
1961 * @cfg {String} buttonPosition (left|right|center) default right
1964 * Create a new Modal Dialog
1965 * @param {Object} config The config object
1968 Roo.bootstrap.Modal = function(config){
1969 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1974 * The raw btnclick event for the button
1975 * @param {Roo.EventObject} e
1979 this.buttons = this.buttons || [];
1982 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1984 title : 'test dialog',
1991 specificTitle: false,
1993 buttonPosition: 'right',
1995 onRender : function(ct, position)
1997 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2000 var cfg = Roo.apply({}, this.getAutoCreate());
2003 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2005 //if (!cfg.name.length) {
2009 cfg.cls += ' ' + this.cls;
2012 cfg.style = this.style;
2014 this.el = Roo.get(document.body).createChild(cfg, position);
2016 //var type = this.el.dom.type;
2018 if(this.tabIndex !== undefined){
2019 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2024 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2025 this.maskEl.enableDisplayMode("block");
2027 //this.el.addClass("x-dlg-modal");
2029 if (this.buttons.length) {
2030 Roo.each(this.buttons, function(bb) {
2031 b = Roo.apply({}, bb);
2032 b.xns = b.xns || Roo.bootstrap;
2033 b.xtype = b.xtype || 'Button';
2034 if (typeof(b.listeners) == 'undefined') {
2035 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2038 var btn = Roo.factory(b);
2040 btn.onRender(this.el.select('.modal-footer div').first());
2044 // render the children.
2047 if(typeof(this.items) != 'undefined'){
2048 var items = this.items;
2051 for(var i =0;i < items.length;i++) {
2052 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2056 this.items = nitems;
2058 this.body = this.el.select('.modal-body',true).first();
2059 this.close = this.el.select('.modal-header .close', true).first();
2060 this.footer = this.el.select('.modal-footer',true).first();
2062 //this.el.addClass([this.fieldClass, this.cls]);
2065 getAutoCreate : function(){
2070 html : this.html || ''
2075 cls : 'modal-title',
2079 if(this.specificTitle){
2085 style : 'display: none',
2088 cls: "modal-dialog",
2091 cls : "modal-content",
2094 cls : 'modal-header',
2106 cls : 'modal-footer',
2110 cls: 'btn-' + this.buttonPosition
2129 getChildContainer : function() {
2131 return this.el.select('.modal-body',true).first();
2134 getButtonContainer : function() {
2135 return this.el.select('.modal-footer div',true).first();
2138 initEvents : function()
2140 this.el.select('.modal-header .close').on('click', this.hide, this);
2142 // this.addxtype(this);
2146 if (!this.rendered) {
2150 this.el.addClass('on');
2151 this.el.removeClass('fade');
2152 this.el.setStyle('display', 'block');
2153 Roo.get(document.body).addClass("x-body-masked");
2154 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2156 this.el.setStyle('zIndex', '10001');
2157 this.fireEvent('show', this);
2163 Roo.log('Modal hide?!');
2165 Roo.get(document.body).removeClass("x-body-masked");
2166 this.el.removeClass('on');
2167 this.el.addClass('fade');
2168 this.el.setStyle('display', 'none');
2169 this.fireEvent('hide', this);
2172 addButton : function(str, cb)
2176 var b = Roo.apply({}, { html : str } );
2177 b.xns = b.xns || Roo.bootstrap;
2178 b.xtype = b.xtype || 'Button';
2179 if (typeof(b.listeners) == 'undefined') {
2180 b.listeners = { click : cb.createDelegate(this) };
2183 var btn = Roo.factory(b);
2185 btn.onRender(this.el.select('.modal-footer div').first());
2191 setDefaultButton : function(btn)
2193 //this.el.select('.modal-footer').()
2195 resizeTo: function(w,h)
2199 setContentSize : function(w, h)
2203 onButtonClick: function(btn,e)
2206 this.fireEvent('btnclick', btn.name, e);
2208 setTitle: function(str) {
2209 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2215 Roo.apply(Roo.bootstrap.Modal, {
2217 * Button config that displays a single OK button
2226 * Button config that displays Yes and No buttons
2242 * Button config that displays OK and Cancel buttons
2257 * Button config that displays Yes, No and Cancel buttons
2279 * messagebox - can be used as a replace
2283 * @class Roo.MessageBox
2284 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2288 Roo.Msg.alert('Status', 'Changes saved successfully.');
2290 // Prompt for user data:
2291 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2293 // process text value...
2297 // Show a dialog using config options:
2299 title:'Save Changes?',
2300 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2301 buttons: Roo.Msg.YESNOCANCEL,
2308 Roo.bootstrap.MessageBox = function(){
2309 var dlg, opt, mask, waitTimer;
2310 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2311 var buttons, activeTextEl, bwidth;
2315 var handleButton = function(button){
2317 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2321 var handleHide = function(){
2323 dlg.el.removeClass(opt.cls);
2326 // Roo.TaskMgr.stop(waitTimer);
2327 // waitTimer = null;
2332 var updateButtons = function(b){
2335 buttons["ok"].hide();
2336 buttons["cancel"].hide();
2337 buttons["yes"].hide();
2338 buttons["no"].hide();
2339 //dlg.footer.dom.style.display = 'none';
2342 dlg.footer.dom.style.display = '';
2343 for(var k in buttons){
2344 if(typeof buttons[k] != "function"){
2347 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2348 width += buttons[k].el.getWidth()+15;
2358 var handleEsc = function(d, k, e){
2359 if(opt && opt.closable !== false){
2369 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2370 * @return {Roo.BasicDialog} The BasicDialog element
2372 getDialog : function(){
2374 dlg = new Roo.bootstrap.Modal( {
2377 //constraintoviewport:false,
2379 //collapsible : false,
2384 //buttonAlign:"center",
2385 closeClick : function(){
2386 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2389 handleButton("cancel");
2394 dlg.on("hide", handleHide);
2396 //dlg.addKeyListener(27, handleEsc);
2398 this.buttons = buttons;
2399 var bt = this.buttonText;
2400 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2401 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2402 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2403 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2405 bodyEl = dlg.body.createChild({
2407 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2408 '<textarea class="roo-mb-textarea"></textarea>' +
2409 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2411 msgEl = bodyEl.dom.firstChild;
2412 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2413 textboxEl.enableDisplayMode();
2414 textboxEl.addKeyListener([10,13], function(){
2415 if(dlg.isVisible() && opt && opt.buttons){
2418 }else if(opt.buttons.yes){
2419 handleButton("yes");
2423 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2424 textareaEl.enableDisplayMode();
2425 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2426 progressEl.enableDisplayMode();
2427 var pf = progressEl.dom.firstChild;
2429 pp = Roo.get(pf.firstChild);
2430 pp.setHeight(pf.offsetHeight);
2438 * Updates the message box body text
2439 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2440 * the XHTML-compliant non-breaking space character '&#160;')
2441 * @return {Roo.MessageBox} This message box
2443 updateText : function(text){
2444 if(!dlg.isVisible() && !opt.width){
2445 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2447 msgEl.innerHTML = text || ' ';
2449 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2450 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2452 Math.min(opt.width || cw , this.maxWidth),
2453 Math.max(opt.minWidth || this.minWidth, bwidth)
2456 activeTextEl.setWidth(w);
2458 if(dlg.isVisible()){
2459 dlg.fixedcenter = false;
2461 // to big, make it scroll. = But as usual stupid IE does not support
2464 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2465 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2466 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2468 bodyEl.dom.style.height = '';
2469 bodyEl.dom.style.overflowY = '';
2472 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2474 bodyEl.dom.style.overflowX = '';
2477 dlg.setContentSize(w, bodyEl.getHeight());
2478 if(dlg.isVisible()){
2479 dlg.fixedcenter = true;
2485 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2486 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2487 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2488 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2489 * @return {Roo.MessageBox} This message box
2491 updateProgress : function(value, text){
2493 this.updateText(text);
2495 if (pp) { // weird bug on my firefox - for some reason this is not defined
2496 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2502 * Returns true if the message box is currently displayed
2503 * @return {Boolean} True if the message box is visible, else false
2505 isVisible : function(){
2506 return dlg && dlg.isVisible();
2510 * Hides the message box if it is displayed
2513 if(this.isVisible()){
2519 * Displays a new message box, or reinitializes an existing message box, based on the config options
2520 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2521 * The following config object properties are supported:
2523 Property Type Description
2524 ---------- --------------- ------------------------------------------------------------------------------------
2525 animEl String/Element An id or Element from which the message box should animate as it opens and
2526 closes (defaults to undefined)
2527 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2528 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2529 closable Boolean False to hide the top-right close button (defaults to true). Note that
2530 progress and wait dialogs will ignore this property and always hide the
2531 close button as they can only be closed programmatically.
2532 cls String A custom CSS class to apply to the message box element
2533 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2534 displayed (defaults to 75)
2535 fn Function A callback function to execute after closing the dialog. The arguments to the
2536 function will be btn (the name of the button that was clicked, if applicable,
2537 e.g. "ok"), and text (the value of the active text field, if applicable).
2538 Progress and wait dialogs will ignore this option since they do not respond to
2539 user actions and can only be closed programmatically, so any required function
2540 should be called by the same code after it closes the dialog.
2541 icon String A CSS class that provides a background image to be used as an icon for
2542 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2543 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2544 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2545 modal Boolean False to allow user interaction with the page while the message box is
2546 displayed (defaults to true)
2547 msg String A string that will replace the existing message box body text (defaults
2548 to the XHTML-compliant non-breaking space character ' ')
2549 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2550 progress Boolean True to display a progress bar (defaults to false)
2551 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2552 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2553 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2554 title String The title text
2555 value String The string value to set into the active textbox element if displayed
2556 wait Boolean True to display a progress bar (defaults to false)
2557 width Number The width of the dialog in pixels
2564 msg: 'Please enter your address:',
2566 buttons: Roo.MessageBox.OKCANCEL,
2569 animEl: 'addAddressBtn'
2572 * @param {Object} config Configuration options
2573 * @return {Roo.MessageBox} This message box
2575 show : function(options)
2578 // this causes nightmares if you show one dialog after another
2579 // especially on callbacks..
2581 if(this.isVisible()){
2584 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2585 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2586 Roo.log("New Dialog Message:" + options.msg )
2587 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2588 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2591 var d = this.getDialog();
2593 d.setTitle(opt.title || " ");
2594 d.close.setDisplayed(opt.closable !== false);
2595 activeTextEl = textboxEl;
2596 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2601 textareaEl.setHeight(typeof opt.multiline == "number" ?
2602 opt.multiline : this.defaultTextHeight);
2603 activeTextEl = textareaEl;
2612 progressEl.setDisplayed(opt.progress === true);
2613 this.updateProgress(0);
2614 activeTextEl.dom.value = opt.value || "";
2616 dlg.setDefaultButton(activeTextEl);
2618 var bs = opt.buttons;
2622 }else if(bs && bs.yes){
2623 db = buttons["yes"];
2625 dlg.setDefaultButton(db);
2627 bwidth = updateButtons(opt.buttons);
2628 this.updateText(opt.msg);
2630 d.el.addClass(opt.cls);
2632 d.proxyDrag = opt.proxyDrag === true;
2633 d.modal = opt.modal !== false;
2634 d.mask = opt.modal !== false ? mask : false;
2636 // force it to the end of the z-index stack so it gets a cursor in FF
2637 document.body.appendChild(dlg.el.dom);
2638 d.animateTarget = null;
2639 d.show(options.animEl);
2645 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2646 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2647 * and closing the message box when the process is complete.
2648 * @param {String} title The title bar text
2649 * @param {String} msg The message box body text
2650 * @return {Roo.MessageBox} This message box
2652 progress : function(title, msg){
2659 minWidth: this.minProgressWidth,
2666 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2667 * If a callback function is passed it will be called after the user clicks the button, and the
2668 * id of the button that was clicked will be passed as the only parameter to the callback
2669 * (could also be the top-right close button).
2670 * @param {String} title The title bar text
2671 * @param {String} msg The message box body text
2672 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2673 * @param {Object} scope (optional) The scope of the callback function
2674 * @return {Roo.MessageBox} This message box
2676 alert : function(title, msg, fn, scope){
2689 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2690 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2691 * You are responsible for closing the message box when the process is complete.
2692 * @param {String} msg The message box body text
2693 * @param {String} title (optional) The title bar text
2694 * @return {Roo.MessageBox} This message box
2696 wait : function(msg, title){
2707 waitTimer = Roo.TaskMgr.start({
2709 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2717 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2718 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2719 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2720 * @param {String} title The title bar text
2721 * @param {String} msg The message box body text
2722 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2723 * @param {Object} scope (optional) The scope of the callback function
2724 * @return {Roo.MessageBox} This message box
2726 confirm : function(title, msg, fn, scope){
2730 buttons: this.YESNO,
2739 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2740 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2741 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2742 * (could also be the top-right close button) and the text that was entered will be passed as the two
2743 * parameters to the callback.
2744 * @param {String} title The title bar text
2745 * @param {String} msg The message box body text
2746 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2747 * @param {Object} scope (optional) The scope of the callback function
2748 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2749 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2750 * @return {Roo.MessageBox} This message box
2752 prompt : function(title, msg, fn, scope, multiline){
2756 buttons: this.OKCANCEL,
2761 multiline: multiline,
2768 * Button config that displays a single OK button
2773 * Button config that displays Yes and No buttons
2776 YESNO : {yes:true, no:true},
2778 * Button config that displays OK and Cancel buttons
2781 OKCANCEL : {ok:true, cancel:true},
2783 * Button config that displays Yes, No and Cancel buttons
2786 YESNOCANCEL : {yes:true, no:true, cancel:true},
2789 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2792 defaultTextHeight : 75,
2794 * The maximum width in pixels of the message box (defaults to 600)
2799 * The minimum width in pixels of the message box (defaults to 100)
2804 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2805 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2808 minProgressWidth : 250,
2810 * An object containing the default button text strings that can be overriden for localized language support.
2811 * Supported properties are: ok, cancel, yes and no.
2812 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2825 * Shorthand for {@link Roo.MessageBox}
2827 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2828 Roo.Msg = Roo.Msg || Roo.MessageBox;
2837 * @class Roo.bootstrap.Navbar
2838 * @extends Roo.bootstrap.Component
2839 * Bootstrap Navbar class
2842 * Create a new Navbar
2843 * @param {Object} config The config object
2847 Roo.bootstrap.Navbar = function(config){
2848 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2852 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2861 getAutoCreate : function(){
2864 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
2868 initEvents :function ()
2870 //Roo.log(this.el.select('.navbar-toggle',true));
2871 this.el.select('.navbar-toggle',true).on('click', function() {
2872 // Roo.log('click');
2873 this.el.select('.navbar-collapse',true).toggleClass('in');
2881 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2883 var size = this.el.getSize();
2884 this.maskEl.setSize(size.width, size.height);
2885 this.maskEl.enableDisplayMode("block");
2894 getChildContainer : function()
2896 if (this.el.select('.collapse').getCount()) {
2897 return this.el.select('.collapse',true).first();
2930 * @class Roo.bootstrap.NavSimplebar
2931 * @extends Roo.bootstrap.Navbar
2932 * Bootstrap Sidebar class
2934 * @cfg {Boolean} inverse is inverted color
2936 * @cfg {String} type (nav | pills | tabs)
2937 * @cfg {Boolean} arrangement stacked | justified
2938 * @cfg {String} align (left | right) alignment
2940 * @cfg {Boolean} main (true|false) main nav bar? default false
2941 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
2943 * @cfg {String} tag (header|footer|nav|div) default is nav
2949 * Create a new Sidebar
2950 * @param {Object} config The config object
2954 Roo.bootstrap.NavSimplebar = function(config){
2955 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
2958 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
2974 getAutoCreate : function(){
2978 tag : this.tag || 'div',
2991 this.type = this.type || 'nav';
2992 if (['tabs','pills'].indexOf(this.type)!==-1) {
2993 cfg.cn[0].cls += ' nav-' + this.type
2997 if (this.type!=='nav') {
2998 Roo.log('nav type must be nav/tabs/pills')
3000 cfg.cn[0].cls += ' navbar-nav'
3006 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3007 cfg.cn[0].cls += ' nav-' + this.arrangement;
3011 if (this.align === 'right') {
3012 cfg.cn[0].cls += ' navbar-right';
3016 cfg.cls += ' navbar-inverse';
3043 * @class Roo.bootstrap.NavHeaderbar
3044 * @extends Roo.bootstrap.NavSimplebar
3045 * Bootstrap Sidebar class
3047 * @cfg {String} brand what is brand
3048 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3049 * @cfg {String} brand_href href of the brand
3050 * @cfg {Boolean} srButton generate the sr-only button (true | false) default true
3051 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3054 * Create a new Sidebar
3055 * @param {Object} config The config object
3059 Roo.bootstrap.NavHeaderbar = function(config){
3060 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3063 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3071 getAutoCreate : function(){
3074 tag: this.nav || 'nav',
3083 cls: 'navbar-header',
3088 cls: 'navbar-toggle',
3089 'data-toggle': 'collapse',
3094 html: 'Toggle navigation'
3116 cls: 'collapse navbar-collapse',
3120 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3122 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3123 cfg.cls += ' navbar-' + this.position;
3125 // tag can override this..
3127 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3130 if (this.brand !== '') {
3133 href: this.brand_href ? this.brand_href : '#',
3134 cls: 'navbar-brand',
3142 cfg.cls += ' main-nav';
3150 initEvents : function()
3152 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3154 if (this.autohide) {
3159 Roo.get(document).on('scroll',function(e) {
3160 var ns = Roo.get(document).getScroll().top;
3161 var os = prevScroll;
3165 ft.removeClass('slideDown');
3166 ft.addClass('slideUp');
3169 ft.removeClass('slideUp');
3170 ft.addClass('slideDown');
3194 * @class Roo.bootstrap.NavSidebar
3195 * @extends Roo.bootstrap.Navbar
3196 * Bootstrap Sidebar class
3199 * Create a new Sidebar
3200 * @param {Object} config The config object
3204 Roo.bootstrap.NavSidebar = function(config){
3205 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3208 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3210 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3212 getAutoCreate : function(){
3217 cls: 'sidebar sidebar-nav'
3239 * @class Roo.bootstrap.NavGroup
3240 * @extends Roo.bootstrap.Component
3241 * Bootstrap NavGroup class
3242 * @cfg {String} align left | right
3243 * @cfg {Boolean} inverse false | true
3244 * @cfg {String} type (nav|pills|tab) default nav
3245 * @cfg {String} navId - reference Id for navbar.
3249 * Create a new nav group
3250 * @param {Object} config The config object
3253 Roo.bootstrap.NavGroup = function(config){
3254 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3257 Roo.bootstrap.NavGroup.register(this);
3261 * Fires when the active item changes
3262 * @param {Roo.bootstrap.NavGroup} this
3263 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3264 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3271 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3282 getAutoCreate : function()
3284 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3291 if (['tabs','pills'].indexOf(this.type)!==-1) {
3292 cfg.cls += ' nav-' + this.type
3294 if (this.type!=='nav') {
3295 Roo.log('nav type must be nav/tabs/pills')
3297 cfg.cls += ' navbar-nav'
3300 if (this.parent().sidebar) {
3303 cls: 'dashboard-menu sidebar-menu'
3309 if (this.form === true) {
3315 if (this.align === 'right') {
3316 cfg.cls += ' navbar-right';
3318 cfg.cls += ' navbar-left';
3322 if (this.align === 'right') {
3323 cfg.cls += ' navbar-right';
3327 cfg.cls += ' navbar-inverse';
3335 * sets the active Navigation item
3336 * @param {Roo.bootstrap.NavItem} the new current navitem
3338 setActiveItem : function(item)
3341 Roo.each(this.navItems, function(v){
3346 v.setActive(false, true);
3353 item.setActive(true, true);
3354 this.fireEvent('changed', this, item, prev);
3359 * gets the active Navigation item
3360 * @return {Roo.bootstrap.NavItem} the current navitem
3362 getActive : function()
3366 Roo.each(this.navItems, function(v){
3377 indexOfNav : function()
3381 Roo.each(this.navItems, function(v,i){
3392 * adds a Navigation item
3393 * @param {Roo.bootstrap.NavItem} the navitem to add
3395 addItem : function(cfg)
3397 var cn = new Roo.bootstrap.NavItem(cfg);
3399 cn.parentId = this.id;
3400 cn.onRender(this.el, null);
3404 * register a Navigation item
3405 * @param {Roo.bootstrap.NavItem} the navitem to add
3407 register : function(item)
3409 this.navItems.push( item);
3410 item.navId = this.navId;
3415 getNavItem: function(tabId)
3418 Roo.each(this.navItems, function(e) {
3419 if (e.tabId == tabId) {
3429 setActiveNext : function()
3431 var i = this.indexOfNav(this.getActive());
3432 if (i > this.navItems.length) {
3435 this.setActiveItem(this.navItems[i+1]);
3437 setActivePrev : function()
3439 var i = this.indexOfNav(this.getActive());
3443 this.setActiveItem(this.navItems[i-1]);
3445 clearWasActive : function(except) {
3446 Roo.each(this.navItems, function(e) {
3447 if (e.tabId != except.tabId && e.was_active) {
3448 e.was_active = false;
3455 getWasActive : function ()
3458 Roo.each(this.navItems, function(e) {
3473 Roo.apply(Roo.bootstrap.NavGroup, {
3477 * register a Navigation Group
3478 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3480 register : function(navgrp)
3482 this.groups[navgrp.navId] = navgrp;
3486 * fetch a Navigation Group based on the navigation ID
3487 * @param {string} the navgroup to add
3488 * @returns {Roo.bootstrap.NavGroup} the navgroup
3490 get: function(navId) {
3491 if (typeof(this.groups[navId]) == 'undefined') {
3493 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3495 return this.groups[navId] ;
3510 * @class Roo.bootstrap.NavItem
3511 * @extends Roo.bootstrap.Component
3512 * Bootstrap Navbar.NavItem class
3513 * @cfg {String} href link to
3514 * @cfg {String} html content of button
3515 * @cfg {String} badge text inside badge
3516 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3517 * @cfg {String} glyphicon name of glyphicon
3518 * @cfg {String} icon name of font awesome icon
3519 * @cfg {Boolean} active Is item active
3520 * @cfg {Boolean} disabled Is item disabled
3522 * @cfg {Boolean} preventDefault (true | false) default false
3523 * @cfg {String} tabId the tab that this item activates.
3524 * @cfg {String} tagtype (a|span) render as a href or span?
3527 * Create a new Navbar Item
3528 * @param {Object} config The config object
3530 Roo.bootstrap.NavItem = function(config){
3531 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3536 * The raw click event for the entire grid.
3537 * @param {Roo.EventObject} e
3542 * Fires when the active item active state changes
3543 * @param {Roo.bootstrap.NavItem} this
3544 * @param {boolean} state the new state
3552 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3560 preventDefault : false,
3567 getAutoCreate : function(){
3575 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3577 if (this.disabled) {
3578 cfg.cls += ' disabled';
3581 if (this.href || this.html || this.glyphicon || this.icon) {
3585 href : this.href || "#",
3586 html: this.html || ''
3591 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3594 if(this.glyphicon) {
3595 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3600 cfg.cn[0].html += " <span class='caret'></span>";
3604 if (this.badge !== '') {
3606 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3614 initEvents: function() {
3615 // Roo.log('init events?');
3616 // Roo.log(this.el.dom);
3617 if (typeof (this.menu) != 'undefined') {
3618 this.menu.parentType = this.xtype;
3619 this.menu.triggerEl = this.el;
3620 this.addxtype(Roo.apply({}, this.menu));
3624 this.el.select('a',true).on('click', this.onClick, this);
3625 // at this point parent should be available..
3626 this.parent().register(this);
3629 onClick : function(e)
3632 if(this.preventDefault){
3635 if (this.disabled) {
3639 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3640 if (tg && tg.transition) {
3641 Roo.log("waiting for the transitionend");
3645 Roo.log("fire event clicked");
3646 if(this.fireEvent('click', this, e) === false){
3650 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3651 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3652 this.parent().setActiveItem(this);
3657 isActive: function () {
3660 setActive : function(state, fire, is_was_active)
3662 if (this.active && !state & this.navId) {
3663 this.was_active = true;
3664 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3666 nv.clearWasActive(this);
3670 this.active = state;
3673 this.el.removeClass('active');
3674 } else if (!this.el.hasClass('active')) {
3675 this.el.addClass('active');
3678 this.fireEvent('changed', this, state);
3681 // show a panel if it's registered and related..
3683 if (!this.navId || !this.tabId || !state || is_was_active) {
3687 var tg = Roo.bootstrap.TabGroup.get(this.navId);
3691 var pan = tg.getPanelByName(this.tabId);
3695 // if we can not flip to new panel - go back to old nav highlight..
3696 if (false == tg.showPanel(pan)) {
3697 var nv = Roo.bootstrap.NavGroup.get(this.navId);
3699 var onav = nv.getWasActive();
3701 onav.setActive(true, false, true);
3710 // this should not be here...
3711 setDisabled : function(state)
3713 this.disabled = state;
3715 this.el.removeClass('disabled');
3716 } else if (!this.el.hasClass('disabled')) {
3717 this.el.addClass('disabled');
3730 * <span> icon </span>
3731 * <span> text </span>
3732 * <span>badge </span>
3736 * @class Roo.bootstrap.NavSidebarItem
3737 * @extends Roo.bootstrap.NavItem
3738 * Bootstrap Navbar.NavSidebarItem class
3740 * Create a new Navbar Button
3741 * @param {Object} config The config object
3743 Roo.bootstrap.NavSidebarItem = function(config){
3744 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3749 * The raw click event for the entire grid.
3750 * @param {Roo.EventObject} e
3755 * Fires when the active item active state changes
3756 * @param {Roo.bootstrap.NavSidebarItem} this
3757 * @param {boolean} state the new state
3765 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3768 getAutoCreate : function(){
3773 href : this.href || '#',
3785 html : this.html || ''
3790 cfg.cls += ' active';
3794 if (this.glyphicon || this.icon) {
3795 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3796 a.cn.push({ tag : 'i', cls : c }) ;
3801 if (this.badge !== '') {
3802 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3806 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3807 a.cls += 'dropdown-toggle treeview' ;
3831 * @class Roo.bootstrap.Row
3832 * @extends Roo.bootstrap.Component
3833 * Bootstrap Row class (contains columns...)
3837 * @param {Object} config The config object
3840 Roo.bootstrap.Row = function(config){
3841 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3844 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3846 getAutoCreate : function(){
3865 * @class Roo.bootstrap.Element
3866 * @extends Roo.bootstrap.Component
3867 * Bootstrap Element class
3868 * @cfg {String} html contents of the element
3869 * @cfg {String} tag tag of the element
3870 * @cfg {String} cls class of the element
3873 * Create a new Element
3874 * @param {Object} config The config object
3877 Roo.bootstrap.Element = function(config){
3878 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3881 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3888 getAutoCreate : function(){
3913 * @class Roo.bootstrap.Pagination
3914 * @extends Roo.bootstrap.Component
3915 * Bootstrap Pagination class
3916 * @cfg {String} size xs | sm | md | lg
3917 * @cfg {Boolean} inverse false | true
3920 * Create a new Pagination
3921 * @param {Object} config The config object
3924 Roo.bootstrap.Pagination = function(config){
3925 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3928 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3934 getAutoCreate : function(){
3940 cfg.cls += ' inverse';
3946 cfg.cls += " " + this.cls;
3964 * @class Roo.bootstrap.PaginationItem
3965 * @extends Roo.bootstrap.Component
3966 * Bootstrap PaginationItem class
3967 * @cfg {String} html text
3968 * @cfg {String} href the link
3969 * @cfg {Boolean} preventDefault (true | false) default true
3970 * @cfg {Boolean} active (true | false) default false
3974 * Create a new PaginationItem
3975 * @param {Object} config The config object
3979 Roo.bootstrap.PaginationItem = function(config){
3980 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3985 * The raw click event for the entire grid.
3986 * @param {Roo.EventObject} e
3992 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
3996 preventDefault: true,
4000 getAutoCreate : function(){
4006 href : this.href ? this.href : '#',
4007 html : this.html ? this.html : ''
4017 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4023 initEvents: function() {
4025 this.el.on('click', this.onClick, this);
4028 onClick : function(e)
4030 Roo.log('PaginationItem on click ');
4031 if(this.preventDefault){
4035 this.fireEvent('click', this, e);
4051 * @class Roo.bootstrap.Slider
4052 * @extends Roo.bootstrap.Component
4053 * Bootstrap Slider class
4056 * Create a new Slider
4057 * @param {Object} config The config object
4060 Roo.bootstrap.Slider = function(config){
4061 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4064 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4066 getAutoCreate : function(){
4070 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4074 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4086 * Ext JS Library 1.1.1
4087 * Copyright(c) 2006-2007, Ext JS, LLC.
4089 * Originally Released Under LGPL - original licence link has changed is not relivant.
4092 * <script type="text/javascript">
4097 * @class Roo.grid.ColumnModel
4098 * @extends Roo.util.Observable
4099 * This is the default implementation of a ColumnModel used by the Grid. It defines
4100 * the columns in the grid.
4103 var colModel = new Roo.grid.ColumnModel([
4104 {header: "Ticker", width: 60, sortable: true, locked: true},
4105 {header: "Company Name", width: 150, sortable: true},
4106 {header: "Market Cap.", width: 100, sortable: true},
4107 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4108 {header: "Employees", width: 100, sortable: true, resizable: false}
4113 * The config options listed for this class are options which may appear in each
4114 * individual column definition.
4115 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4117 * @param {Object} config An Array of column config objects. See this class's
4118 * config objects for details.
4120 Roo.grid.ColumnModel = function(config){
4122 * The config passed into the constructor
4124 this.config = config;
4127 // if no id, create one
4128 // if the column does not have a dataIndex mapping,
4129 // map it to the order it is in the config
4130 for(var i = 0, len = config.length; i < len; i++){
4132 if(typeof c.dataIndex == "undefined"){
4135 if(typeof c.renderer == "string"){
4136 c.renderer = Roo.util.Format[c.renderer];
4138 if(typeof c.id == "undefined"){
4141 if(c.editor && c.editor.xtype){
4142 c.editor = Roo.factory(c.editor, Roo.grid);
4144 if(c.editor && c.editor.isFormField){
4145 c.editor = new Roo.grid.GridEditor(c.editor);
4147 this.lookup[c.id] = c;
4151 * The width of columns which have no width specified (defaults to 100)
4154 this.defaultWidth = 100;
4157 * Default sortable of columns which have no sortable specified (defaults to false)
4160 this.defaultSortable = false;
4164 * @event widthchange
4165 * Fires when the width of a column changes.
4166 * @param {ColumnModel} this
4167 * @param {Number} columnIndex The column index
4168 * @param {Number} newWidth The new width
4170 "widthchange": true,
4172 * @event headerchange
4173 * Fires when the text of a header changes.
4174 * @param {ColumnModel} this
4175 * @param {Number} columnIndex The column index
4176 * @param {Number} newText The new header text
4178 "headerchange": true,
4180 * @event hiddenchange
4181 * Fires when a column is hidden or "unhidden".
4182 * @param {ColumnModel} this
4183 * @param {Number} columnIndex The column index
4184 * @param {Boolean} hidden true if hidden, false otherwise
4186 "hiddenchange": true,
4188 * @event columnmoved
4189 * Fires when a column is moved.
4190 * @param {ColumnModel} this
4191 * @param {Number} oldIndex
4192 * @param {Number} newIndex
4194 "columnmoved" : true,
4196 * @event columlockchange
4197 * Fires when a column's locked state is changed
4198 * @param {ColumnModel} this
4199 * @param {Number} colIndex
4200 * @param {Boolean} locked true if locked
4202 "columnlockchange" : true
4204 Roo.grid.ColumnModel.superclass.constructor.call(this);
4206 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4208 * @cfg {String} header The header text to display in the Grid view.
4211 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4212 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4213 * specified, the column's index is used as an index into the Record's data Array.
4216 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4217 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4220 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4221 * Defaults to the value of the {@link #defaultSortable} property.
4222 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4225 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4228 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4231 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4234 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4237 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4238 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4239 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4240 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4243 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4246 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4250 * Returns the id of the column at the specified index.
4251 * @param {Number} index The column index
4252 * @return {String} the id
4254 getColumnId : function(index){
4255 return this.config[index].id;
4259 * Returns the column for a specified id.
4260 * @param {String} id The column id
4261 * @return {Object} the column
4263 getColumnById : function(id){
4264 return this.lookup[id];
4269 * Returns the column for a specified dataIndex.
4270 * @param {String} dataIndex The column dataIndex
4271 * @return {Object|Boolean} the column or false if not found
4273 getColumnByDataIndex: function(dataIndex){
4274 var index = this.findColumnIndex(dataIndex);
4275 return index > -1 ? this.config[index] : false;
4279 * Returns the index for a specified column id.
4280 * @param {String} id The column id
4281 * @return {Number} the index, or -1 if not found
4283 getIndexById : function(id){
4284 for(var i = 0, len = this.config.length; i < len; i++){
4285 if(this.config[i].id == id){
4293 * Returns the index for a specified column dataIndex.
4294 * @param {String} dataIndex The column dataIndex
4295 * @return {Number} the index, or -1 if not found
4298 findColumnIndex : function(dataIndex){
4299 for(var i = 0, len = this.config.length; i < len; i++){
4300 if(this.config[i].dataIndex == dataIndex){
4308 moveColumn : function(oldIndex, newIndex){
4309 var c = this.config[oldIndex];
4310 this.config.splice(oldIndex, 1);
4311 this.config.splice(newIndex, 0, c);
4312 this.dataMap = null;
4313 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4316 isLocked : function(colIndex){
4317 return this.config[colIndex].locked === true;
4320 setLocked : function(colIndex, value, suppressEvent){
4321 if(this.isLocked(colIndex) == value){
4324 this.config[colIndex].locked = value;
4326 this.fireEvent("columnlockchange", this, colIndex, value);
4330 getTotalLockedWidth : function(){
4332 for(var i = 0; i < this.config.length; i++){
4333 if(this.isLocked(i) && !this.isHidden(i)){
4334 this.totalWidth += this.getColumnWidth(i);
4340 getLockedCount : function(){
4341 for(var i = 0, len = this.config.length; i < len; i++){
4342 if(!this.isLocked(i)){
4349 * Returns the number of columns.
4352 getColumnCount : function(visibleOnly){
4353 if(visibleOnly === true){
4355 for(var i = 0, len = this.config.length; i < len; i++){
4356 if(!this.isHidden(i)){
4362 return this.config.length;
4366 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4367 * @param {Function} fn
4368 * @param {Object} scope (optional)
4369 * @return {Array} result
4371 getColumnsBy : function(fn, scope){
4373 for(var i = 0, len = this.config.length; i < len; i++){
4374 var c = this.config[i];
4375 if(fn.call(scope||this, c, i) === true){
4383 * Returns true if the specified column is sortable.
4384 * @param {Number} col The column index
4387 isSortable : function(col){
4388 if(typeof this.config[col].sortable == "undefined"){
4389 return this.defaultSortable;
4391 return this.config[col].sortable;
4395 * Returns the rendering (formatting) function defined for the column.
4396 * @param {Number} col The column index.
4397 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4399 getRenderer : function(col){
4400 if(!this.config[col].renderer){
4401 return Roo.grid.ColumnModel.defaultRenderer;
4403 return this.config[col].renderer;
4407 * Sets the rendering (formatting) function for a column.
4408 * @param {Number} col The column index
4409 * @param {Function} fn The function to use to process the cell's raw data
4410 * to return HTML markup for the grid view. The render function is called with
4411 * the following parameters:<ul>
4412 * <li>Data value.</li>
4413 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4414 * <li>css A CSS style string to apply to the table cell.</li>
4415 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4416 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4417 * <li>Row index</li>
4418 * <li>Column index</li>
4419 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4421 setRenderer : function(col, fn){
4422 this.config[col].renderer = fn;
4426 * Returns the width for the specified column.
4427 * @param {Number} col The column index
4430 getColumnWidth : function(col){
4431 return this.config[col].width * 1 || this.defaultWidth;
4435 * Sets the width for a column.
4436 * @param {Number} col The column index
4437 * @param {Number} width The new width
4439 setColumnWidth : function(col, width, suppressEvent){
4440 this.config[col].width = width;
4441 this.totalWidth = null;
4443 this.fireEvent("widthchange", this, col, width);
4448 * Returns the total width of all columns.
4449 * @param {Boolean} includeHidden True to include hidden column widths
4452 getTotalWidth : function(includeHidden){
4453 if(!this.totalWidth){
4454 this.totalWidth = 0;
4455 for(var i = 0, len = this.config.length; i < len; i++){
4456 if(includeHidden || !this.isHidden(i)){
4457 this.totalWidth += this.getColumnWidth(i);
4461 return this.totalWidth;
4465 * Returns the header for the specified column.
4466 * @param {Number} col The column index
4469 getColumnHeader : function(col){
4470 return this.config[col].header;
4474 * Sets the header for a column.
4475 * @param {Number} col The column index
4476 * @param {String} header The new header
4478 setColumnHeader : function(col, header){
4479 this.config[col].header = header;
4480 this.fireEvent("headerchange", this, col, header);
4484 * Returns the tooltip for the specified column.
4485 * @param {Number} col The column index
4488 getColumnTooltip : function(col){
4489 return this.config[col].tooltip;
4492 * Sets the tooltip for a column.
4493 * @param {Number} col The column index
4494 * @param {String} tooltip The new tooltip
4496 setColumnTooltip : function(col, tooltip){
4497 this.config[col].tooltip = tooltip;
4501 * Returns the dataIndex for the specified column.
4502 * @param {Number} col The column index
4505 getDataIndex : function(col){
4506 return this.config[col].dataIndex;
4510 * Sets the dataIndex for a column.
4511 * @param {Number} col The column index
4512 * @param {Number} dataIndex The new dataIndex
4514 setDataIndex : function(col, dataIndex){
4515 this.config[col].dataIndex = dataIndex;
4521 * Returns true if the cell is editable.
4522 * @param {Number} colIndex The column index
4523 * @param {Number} rowIndex The row index
4526 isCellEditable : function(colIndex, rowIndex){
4527 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4531 * Returns the editor defined for the cell/column.
4532 * return false or null to disable editing.
4533 * @param {Number} colIndex The column index
4534 * @param {Number} rowIndex The row index
4537 getCellEditor : function(colIndex, rowIndex){
4538 return this.config[colIndex].editor;
4542 * Sets if a column is editable.
4543 * @param {Number} col The column index
4544 * @param {Boolean} editable True if the column is editable
4546 setEditable : function(col, editable){
4547 this.config[col].editable = editable;
4552 * Returns true if the column is hidden.
4553 * @param {Number} colIndex The column index
4556 isHidden : function(colIndex){
4557 return this.config[colIndex].hidden;
4562 * Returns true if the column width cannot be changed
4564 isFixed : function(colIndex){
4565 return this.config[colIndex].fixed;
4569 * Returns true if the column can be resized
4572 isResizable : function(colIndex){
4573 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4576 * Sets if a column is hidden.
4577 * @param {Number} colIndex The column index
4578 * @param {Boolean} hidden True if the column is hidden
4580 setHidden : function(colIndex, hidden){
4581 this.config[colIndex].hidden = hidden;
4582 this.totalWidth = null;
4583 this.fireEvent("hiddenchange", this, colIndex, hidden);
4587 * Sets the editor for a column.
4588 * @param {Number} col The column index
4589 * @param {Object} editor The editor object
4591 setEditor : function(col, editor){
4592 this.config[col].editor = editor;
4596 Roo.grid.ColumnModel.defaultRenderer = function(value){
4597 if(typeof value == "string" && value.length < 1){
4603 // Alias for backwards compatibility
4604 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4607 * Ext JS Library 1.1.1
4608 * Copyright(c) 2006-2007, Ext JS, LLC.
4610 * Originally Released Under LGPL - original licence link has changed is not relivant.
4613 * <script type="text/javascript">
4617 * @class Roo.LoadMask
4618 * A simple utility class for generically masking elements while loading data. If the element being masked has
4619 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4620 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4621 * element's UpdateManager load indicator and will be destroyed after the initial load.
4623 * Create a new LoadMask
4624 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4625 * @param {Object} config The config object
4627 Roo.LoadMask = function(el, config){
4628 this.el = Roo.get(el);
4629 Roo.apply(this, config);
4631 this.store.on('beforeload', this.onBeforeLoad, this);
4632 this.store.on('load', this.onLoad, this);
4633 this.store.on('loadexception', this.onLoadException, this);
4634 this.removeMask = false;
4636 var um = this.el.getUpdateManager();
4637 um.showLoadIndicator = false; // disable the default indicator
4638 um.on('beforeupdate', this.onBeforeLoad, this);
4639 um.on('update', this.onLoad, this);
4640 um.on('failure', this.onLoad, this);
4641 this.removeMask = true;
4645 Roo.LoadMask.prototype = {
4647 * @cfg {Boolean} removeMask
4648 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4649 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4653 * The text to display in a centered loading message box (defaults to 'Loading...')
4657 * @cfg {String} msgCls
4658 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4660 msgCls : 'x-mask-loading',
4663 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4669 * Disables the mask to prevent it from being displayed
4671 disable : function(){
4672 this.disabled = true;
4676 * Enables the mask so that it can be displayed
4678 enable : function(){
4679 this.disabled = false;
4682 onLoadException : function()
4686 if (typeof(arguments[3]) != 'undefined') {
4687 Roo.MessageBox.alert("Error loading",arguments[3]);
4691 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4692 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4701 this.el.unmask(this.removeMask);
4706 this.el.unmask(this.removeMask);
4710 onBeforeLoad : function(){
4712 this.el.mask(this.msg, this.msgCls);
4717 destroy : function(){
4719 this.store.un('beforeload', this.onBeforeLoad, this);
4720 this.store.un('load', this.onLoad, this);
4721 this.store.un('loadexception', this.onLoadException, this);
4723 var um = this.el.getUpdateManager();
4724 um.un('beforeupdate', this.onBeforeLoad, this);
4725 um.un('update', this.onLoad, this);
4726 um.un('failure', this.onLoad, this);
4737 * @class Roo.bootstrap.Table
4738 * @extends Roo.bootstrap.Component
4739 * Bootstrap Table class
4740 * @cfg {String} cls table class
4741 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4742 * @cfg {String} bgcolor Specifies the background color for a table
4743 * @cfg {Number} border Specifies whether the table cells should have borders or not
4744 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4745 * @cfg {Number} cellspacing Specifies the space between cells
4746 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4747 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4748 * @cfg {String} sortable Specifies that the table should be sortable
4749 * @cfg {String} summary Specifies a summary of the content of a table
4750 * @cfg {Number} width Specifies the width of a table
4751 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4753 * @cfg {boolean} striped Should the rows be alternative striped
4754 * @cfg {boolean} bordered Add borders to the table
4755 * @cfg {boolean} hover Add hover highlighting
4756 * @cfg {boolean} condensed Format condensed
4757 * @cfg {boolean} responsive Format condensed
4758 * @cfg {Boolean} loadMask (true|false) default false
4759 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4760 * @cfg {Boolean} thead (true|false) generate thead, default true
4761 * @cfg {Boolean} RowSelection (true|false) default false
4762 * @cfg {Boolean} CellSelection (true|false) default false
4764 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4768 * Create a new Table
4769 * @param {Object} config The config object
4772 Roo.bootstrap.Table = function(config){
4773 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4776 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4777 this.sm = this.selModel;
4778 this.sm.xmodule = this.xmodule || false;
4780 if (this.cm && typeof(this.cm.config) == 'undefined') {
4781 this.colModel = new Roo.grid.ColumnModel(this.cm);
4782 this.cm = this.colModel;
4783 this.cm.xmodule = this.xmodule || false;
4786 this.store= Roo.factory(this.store, Roo.data);
4787 this.ds = this.store;
4788 this.ds.xmodule = this.xmodule || false;
4791 if (this.footer && this.store) {
4792 this.footer.dataSource = this.ds;
4793 this.footer = Roo.factory(this.footer);
4800 * Fires when a cell is clicked
4801 * @param {Roo.bootstrap.Table} this
4802 * @param {Roo.Element} el
4803 * @param {Number} rowIndex
4804 * @param {Number} columnIndex
4805 * @param {Roo.EventObject} e
4809 * @event celldblclick
4810 * Fires when a cell is double clicked
4811 * @param {Roo.bootstrap.Table} this
4812 * @param {Roo.Element} el
4813 * @param {Number} rowIndex
4814 * @param {Number} columnIndex
4815 * @param {Roo.EventObject} e
4817 "celldblclick" : true,
4820 * Fires when a row is clicked
4821 * @param {Roo.bootstrap.Table} this
4822 * @param {Roo.Element} el
4823 * @param {Number} rowIndex
4824 * @param {Roo.EventObject} e
4828 * @event rowdblclick
4829 * Fires when a row is double clicked
4830 * @param {Roo.bootstrap.Table} this
4831 * @param {Roo.Element} el
4832 * @param {Number} rowIndex
4833 * @param {Roo.EventObject} e
4835 "rowdblclick" : true,
4838 * Fires when a mouseover occur
4839 * @param {Roo.bootstrap.Table} this
4840 * @param {Roo.Element} el
4841 * @param {Number} rowIndex
4842 * @param {Number} columnIndex
4843 * @param {Roo.EventObject} e
4848 * Fires when a mouseout occur
4849 * @param {Roo.bootstrap.Table} this
4850 * @param {Roo.Element} el
4851 * @param {Number} rowIndex
4852 * @param {Number} columnIndex
4853 * @param {Roo.EventObject} e
4858 * Fires when a row is rendered, so you can change add a style to it.
4859 * @param {Roo.bootstrap.Table} this
4860 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
4867 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4891 RowSelection : false,
4892 CellSelection : false,
4895 // Roo.Element - the tbody
4898 getAutoCreate : function(){
4899 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4908 cfg.cls += ' table-striped';
4912 cfg.cls += ' table-hover';
4914 if (this.bordered) {
4915 cfg.cls += ' table-bordered';
4917 if (this.condensed) {
4918 cfg.cls += ' table-condensed';
4920 if (this.responsive) {
4921 cfg.cls += ' table-responsive';
4925 cfg.cls+= ' ' +this.cls;
4928 // this lot should be simplifed...
4931 cfg.align=this.align;
4934 cfg.bgcolor=this.bgcolor;
4937 cfg.border=this.border;
4939 if (this.cellpadding) {
4940 cfg.cellpadding=this.cellpadding;
4942 if (this.cellspacing) {
4943 cfg.cellspacing=this.cellspacing;
4946 cfg.frame=this.frame;
4949 cfg.rules=this.rules;
4951 if (this.sortable) {
4952 cfg.sortable=this.sortable;
4955 cfg.summary=this.summary;
4958 cfg.width=this.width;
4961 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
4964 if(this.store || this.cm){
4966 cfg.cn.push(this.renderHeader());
4969 cfg.cn.push(this.renderBody());
4972 cfg.cn.push(this.renderFooter());
4975 cfg.cls+= ' TableGrid';
4978 return { cn : [ cfg ] };
4981 initEvents : function()
4983 if(!this.store || !this.cm){
4987 //Roo.log('initEvents with ds!!!!');
4989 this.mainBody = this.el.select('tbody', true).first();
4994 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4995 e.on('click', _this.sort, _this);
4998 this.el.on("click", this.onClick, this);
4999 this.el.on("dblclick", this.onDblClick, this);
5001 this.parent().el.setStyle('position', 'relative');
5003 this.footer.parentId = this.id;
5004 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5007 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5009 this.store.on('load', this.onLoad, this);
5010 this.store.on('beforeload', this.onBeforeLoad, this);
5011 this.store.on('update', this.onUpdate, this);
5015 onMouseover : function(e, el)
5017 var cell = Roo.get(el);
5023 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5024 cell = cell.findParent('td', false, true);
5027 var row = cell.findParent('tr', false, true);
5028 var cellIndex = cell.dom.cellIndex;
5029 var rowIndex = row.dom.rowIndex - 1; // start from 0
5031 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5035 onMouseout : function(e, el)
5037 var cell = Roo.get(el);
5043 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5044 cell = cell.findParent('td', false, true);
5047 var row = cell.findParent('tr', false, true);
5048 var cellIndex = cell.dom.cellIndex;
5049 var rowIndex = row.dom.rowIndex - 1; // start from 0
5051 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5055 onClick : function(e, el)
5057 var cell = Roo.get(el);
5059 if(!cell || (!this.CellSelection && !this.RowSelection)){
5064 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5065 cell = cell.findParent('td', false, true);
5068 var row = cell.findParent('tr', false, true);
5069 var cellIndex = cell.dom.cellIndex;
5070 var rowIndex = row.dom.rowIndex - 1;
5072 if(this.CellSelection){
5073 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5076 if(this.RowSelection){
5077 this.fireEvent('rowclick', this, row, rowIndex, e);
5083 onDblClick : function(e,el)
5085 var cell = Roo.get(el);
5087 if(!cell || (!this.CellSelection && !this.RowSelection)){
5091 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5092 cell = cell.findParent('td', false, true);
5095 var row = cell.findParent('tr', false, true);
5096 var cellIndex = cell.dom.cellIndex;
5097 var rowIndex = row.dom.rowIndex - 1;
5099 if(this.CellSelection){
5100 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5103 if(this.RowSelection){
5104 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5108 sort : function(e,el)
5110 var col = Roo.get(el)
5112 if(!col.hasClass('sortable')){
5116 var sort = col.attr('sort');
5119 if(col.hasClass('glyphicon-arrow-up')){
5123 this.store.sortInfo = {field : sort, direction : dir};
5126 Roo.log("calling footer first");
5127 this.footer.onClick('first');
5130 this.store.load({ params : { start : 0 } });
5134 renderHeader : function()
5143 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5145 var config = cm.config[i];
5150 html: cm.getColumnHeader(i)
5153 if(typeof(config.hidden) != 'undefined' && config.hidden){
5154 c.style += ' display:none;';
5157 if(typeof(config.dataIndex) != 'undefined'){
5158 c.sort = config.dataIndex;
5161 if(typeof(config.sortable) != 'undefined' && config.sortable){
5165 if(typeof(config.align) != 'undefined' && config.align.length){
5166 c.style += ' text-align:' + config.align + ';';
5169 if(typeof(config.width) != 'undefined'){
5170 c.style += ' width:' + config.width + 'px;';
5179 renderBody : function()
5189 colspan : this.cm.getColumnCount()
5199 renderFooter : function()
5209 colspan : this.cm.getColumnCount()
5223 Roo.log('ds onload');
5228 var ds = this.store;
5230 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5231 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5233 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5234 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5237 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5238 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5242 var tbody = this.mainBody;
5244 if(ds.getCount() > 0){
5245 ds.data.each(function(d,rowIndex){
5246 var row = this.renderRow(cm, ds, rowIndex);
5248 tbody.createChild(row);
5252 if(row.cellObjects.length){
5253 Roo.each(row.cellObjects, function(r){
5254 _this.renderCellObject(r);
5261 Roo.each(this.el.select('tbody td', true).elements, function(e){
5262 e.on('mouseover', _this.onMouseover, _this);
5265 Roo.each(this.el.select('tbody td', true).elements, function(e){
5266 e.on('mouseout', _this.onMouseout, _this);
5269 //if(this.loadMask){
5270 // this.maskEl.hide();
5275 onUpdate : function(ds,record)
5277 this.refreshRow(record);
5279 onRemove : function(ds, record, index, isUpdate){
5280 if(isUpdate !== true){
5281 this.fireEvent("beforerowremoved", this, index, record);
5283 var bt = this.mainBody.dom;
5285 bt.removeChild(bt.rows[index]);
5288 if(isUpdate !== true){
5289 //this.stripeRows(index);
5290 //this.syncRowHeights(index, index);
5292 this.fireEvent("rowremoved", this, index, record);
5297 refreshRow : function(record){
5298 var ds = this.store, index;
5299 if(typeof record == 'number'){
5301 record = ds.getAt(index);
5303 index = ds.indexOf(record);
5305 this.insertRow(ds, index, true);
5306 this.onRemove(ds, record, index+1, true);
5307 //this.syncRowHeights(index, index);
5309 this.fireEvent("rowupdated", this, index, record);
5312 insertRow : function(dm, rowIndex, isUpdate){
5315 this.fireEvent("beforerowsinserted", this, rowIndex);
5317 //var s = this.getScrollState();
5318 var row = this.renderRow(this.cm, this.store, rowIndex);
5319 // insert before rowIndex..
5320 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5324 if(row.cellObjects.length){
5325 Roo.each(row.cellObjects, function(r){
5326 _this.renderCellObject(r);
5331 this.fireEvent("rowsinserted", this, rowIndex);
5332 //this.syncRowHeights(firstRow, lastRow);
5333 //this.stripeRows(firstRow);
5340 getRowDom : function(rowIndex)
5342 // not sure if I need to check this.. but let's do it anyway..
5343 return (this.mainBody.dom.rows && (rowIndex-1) < this.mainBody.dom.rows.length ) ?
5344 this.mainBody.dom.rows[rowIndex] : false
5346 // returns the object tree for a tr..
5349 renderRow : function(cm, ds, rowIndex) {
5351 var d = ds.getAt(rowIndex);
5358 var cellObjects = [];
5360 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5361 var config = cm.config[i];
5363 var renderer = cm.getRenderer(i);
5367 if(typeof(renderer) !== 'undefined'){
5368 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5370 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5371 // and are rendered into the cells after the row is rendered - using the id for the element.
5373 if(typeof(value) === 'object'){
5383 rowIndex : rowIndex,
5388 this.fireEvent('rowclass', this, rowcfg);
5392 cls : rowcfg.rowClass,
5394 html: (typeof(value) === 'object') ? '' : value
5401 if(typeof(config.hidden) != 'undefined' && config.hidden){
5402 td.style += ' display:none;';
5405 if(typeof(config.align) != 'undefined' && config.align.length){
5406 td.style += ' text-align:' + config.align + ';';
5409 if(typeof(config.width) != 'undefined'){
5410 td.style += ' width:' + config.width + 'px;';
5417 row.cellObjects = cellObjects;
5425 onBeforeLoad : function()
5427 //Roo.log('ds onBeforeLoad');
5431 //if(this.loadMask){
5432 // this.maskEl.show();
5438 this.el.select('tbody', true).first().dom.innerHTML = '';
5441 getSelectionModel : function(){
5443 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5445 return this.selModel;
5448 * Render the Roo.bootstrap object from renderder
5450 renderCellObject : function(r)
5454 var t = r.cfg.render(r.container);
5457 Roo.each(r.cfg.cn, function(c){
5459 container: t.getChildContainer(),
5462 _this.renderCellObject(child);
5479 * @class Roo.bootstrap.TableCell
5480 * @extends Roo.bootstrap.Component
5481 * Bootstrap TableCell class
5482 * @cfg {String} html cell contain text
5483 * @cfg {String} cls cell class
5484 * @cfg {String} tag cell tag (td|th) default td
5485 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5486 * @cfg {String} align Aligns the content in a cell
5487 * @cfg {String} axis Categorizes cells
5488 * @cfg {String} bgcolor Specifies the background color of a cell
5489 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5490 * @cfg {Number} colspan Specifies the number of columns a cell should span
5491 * @cfg {String} headers Specifies one or more header cells a cell is related to
5492 * @cfg {Number} height Sets the height of a cell
5493 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5494 * @cfg {Number} rowspan Sets the number of rows a cell should span
5495 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5496 * @cfg {String} valign Vertical aligns the content in a cell
5497 * @cfg {Number} width Specifies the width of a cell
5500 * Create a new TableCell
5501 * @param {Object} config The config object
5504 Roo.bootstrap.TableCell = function(config){
5505 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5508 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5528 getAutoCreate : function(){
5529 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5549 cfg.align=this.align
5555 cfg.bgcolor=this.bgcolor
5558 cfg.charoff=this.charoff
5561 cfg.colspan=this.colspan
5564 cfg.headers=this.headers
5567 cfg.height=this.height
5570 cfg.nowrap=this.nowrap
5573 cfg.rowspan=this.rowspan
5576 cfg.scope=this.scope
5579 cfg.valign=this.valign
5582 cfg.width=this.width
5601 * @class Roo.bootstrap.TableRow
5602 * @extends Roo.bootstrap.Component
5603 * Bootstrap TableRow class
5604 * @cfg {String} cls row class
5605 * @cfg {String} align Aligns the content in a table row
5606 * @cfg {String} bgcolor Specifies a background color for a table row
5607 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5608 * @cfg {String} valign Vertical aligns the content in a table row
5611 * Create a new TableRow
5612 * @param {Object} config The config object
5615 Roo.bootstrap.TableRow = function(config){
5616 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5619 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5627 getAutoCreate : function(){
5628 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5638 cfg.align = this.align;
5641 cfg.bgcolor = this.bgcolor;
5644 cfg.charoff = this.charoff;
5647 cfg.valign = this.valign;
5665 * @class Roo.bootstrap.TableBody
5666 * @extends Roo.bootstrap.Component
5667 * Bootstrap TableBody class
5668 * @cfg {String} cls element class
5669 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5670 * @cfg {String} align Aligns the content inside the element
5671 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5672 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5675 * Create a new TableBody
5676 * @param {Object} config The config object
5679 Roo.bootstrap.TableBody = function(config){
5680 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5683 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5691 getAutoCreate : function(){
5692 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5706 cfg.align = this.align;
5709 cfg.charoff = this.charoff;
5712 cfg.valign = this.valign;
5719 // initEvents : function()
5726 // this.store = Roo.factory(this.store, Roo.data);
5727 // this.store.on('load', this.onLoad, this);
5729 // this.store.load();
5733 // onLoad: function ()
5735 // this.fireEvent('load', this);
5745 * Ext JS Library 1.1.1
5746 * Copyright(c) 2006-2007, Ext JS, LLC.
5748 * Originally Released Under LGPL - original licence link has changed is not relivant.
5751 * <script type="text/javascript">
5754 // as we use this in bootstrap.
5755 Roo.namespace('Roo.form');
5757 * @class Roo.form.Action
5758 * Internal Class used to handle form actions
5760 * @param {Roo.form.BasicForm} el The form element or its id
5761 * @param {Object} config Configuration options
5766 // define the action interface
5767 Roo.form.Action = function(form, options){
5769 this.options = options || {};
5772 * Client Validation Failed
5775 Roo.form.Action.CLIENT_INVALID = 'client';
5777 * Server Validation Failed
5780 Roo.form.Action.SERVER_INVALID = 'server';
5782 * Connect to Server Failed
5785 Roo.form.Action.CONNECT_FAILURE = 'connect';
5787 * Reading Data from Server Failed
5790 Roo.form.Action.LOAD_FAILURE = 'load';
5792 Roo.form.Action.prototype = {
5794 failureType : undefined,
5795 response : undefined,
5799 run : function(options){
5804 success : function(response){
5809 handleResponse : function(response){
5813 // default connection failure
5814 failure : function(response){
5816 this.response = response;
5817 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5818 this.form.afterAction(this, false);
5821 processResponse : function(response){
5822 this.response = response;
5823 if(!response.responseText){
5826 this.result = this.handleResponse(response);
5830 // utility functions used internally
5831 getUrl : function(appendParams){
5832 var url = this.options.url || this.form.url || this.form.el.dom.action;
5834 var p = this.getParams();
5836 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5842 getMethod : function(){
5843 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5846 getParams : function(){
5847 var bp = this.form.baseParams;
5848 var p = this.options.params;
5850 if(typeof p == "object"){
5851 p = Roo.urlEncode(Roo.applyIf(p, bp));
5852 }else if(typeof p == 'string' && bp){
5853 p += '&' + Roo.urlEncode(bp);
5856 p = Roo.urlEncode(bp);
5861 createCallback : function(){
5863 success: this.success,
5864 failure: this.failure,
5866 timeout: (this.form.timeout*1000),
5867 upload: this.form.fileUpload ? this.success : undefined
5872 Roo.form.Action.Submit = function(form, options){
5873 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
5876 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
5879 haveProgress : false,
5880 uploadComplete : false,
5882 // uploadProgress indicator.
5883 uploadProgress : function()
5885 if (!this.form.progressUrl) {
5889 if (!this.haveProgress) {
5890 Roo.MessageBox.progress("Uploading", "Uploading");
5892 if (this.uploadComplete) {
5893 Roo.MessageBox.hide();
5897 this.haveProgress = true;
5899 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
5901 var c = new Roo.data.Connection();
5903 url : this.form.progressUrl,
5908 success : function(req){
5909 //console.log(data);
5913 rdata = Roo.decode(req.responseText)
5915 Roo.log("Invalid data from server..");
5919 if (!rdata || !rdata.success) {
5921 Roo.MessageBox.alert(Roo.encode(rdata));
5924 var data = rdata.data;
5926 if (this.uploadComplete) {
5927 Roo.MessageBox.hide();
5932 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
5933 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
5936 this.uploadProgress.defer(2000,this);
5939 failure: function(data) {
5940 Roo.log('progress url failed ');
5951 // run get Values on the form, so it syncs any secondary forms.
5952 this.form.getValues();
5954 var o = this.options;
5955 var method = this.getMethod();
5956 var isPost = method == 'POST';
5957 if(o.clientValidation === false || this.form.isValid()){
5959 if (this.form.progressUrl) {
5960 this.form.findField('UPLOAD_IDENTIFIER').setValue(
5961 (new Date() * 1) + '' + Math.random());
5966 Roo.Ajax.request(Roo.apply(this.createCallback(), {
5967 form:this.form.el.dom,
5968 url:this.getUrl(!isPost),
5970 params:isPost ? this.getParams() : null,
5971 isUpload: this.form.fileUpload
5974 this.uploadProgress();
5976 }else if (o.clientValidation !== false){ // client validation failed
5977 this.failureType = Roo.form.Action.CLIENT_INVALID;
5978 this.form.afterAction(this, false);
5982 success : function(response)
5984 this.uploadComplete= true;
5985 if (this.haveProgress) {
5986 Roo.MessageBox.hide();
5990 var result = this.processResponse(response);
5991 if(result === true || result.success){
5992 this.form.afterAction(this, true);
5996 this.form.markInvalid(result.errors);
5997 this.failureType = Roo.form.Action.SERVER_INVALID;
5999 this.form.afterAction(this, false);
6001 failure : function(response)
6003 this.uploadComplete= true;
6004 if (this.haveProgress) {
6005 Roo.MessageBox.hide();
6008 this.response = response;
6009 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6010 this.form.afterAction(this, false);
6013 handleResponse : function(response){
6014 if(this.form.errorReader){
6015 var rs = this.form.errorReader.read(response);
6018 for(var i = 0, len = rs.records.length; i < len; i++) {
6019 var r = rs.records[i];
6023 if(errors.length < 1){
6027 success : rs.success,
6033 ret = Roo.decode(response.responseText);
6037 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6047 Roo.form.Action.Load = function(form, options){
6048 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6049 this.reader = this.form.reader;
6052 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6057 Roo.Ajax.request(Roo.apply(
6058 this.createCallback(), {
6059 method:this.getMethod(),
6060 url:this.getUrl(false),
6061 params:this.getParams()
6065 success : function(response){
6067 var result = this.processResponse(response);
6068 if(result === true || !result.success || !result.data){
6069 this.failureType = Roo.form.Action.LOAD_FAILURE;
6070 this.form.afterAction(this, false);
6073 this.form.clearInvalid();
6074 this.form.setValues(result.data);
6075 this.form.afterAction(this, true);
6078 handleResponse : function(response){
6079 if(this.form.reader){
6080 var rs = this.form.reader.read(response);
6081 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6083 success : rs.success,
6087 return Roo.decode(response.responseText);
6091 Roo.form.Action.ACTION_TYPES = {
6092 'load' : Roo.form.Action.Load,
6093 'submit' : Roo.form.Action.Submit
6102 * @class Roo.bootstrap.Form
6103 * @extends Roo.bootstrap.Component
6104 * Bootstrap Form class
6105 * @cfg {String} method GET | POST (default POST)
6106 * @cfg {String} labelAlign top | left (default top)
6107 * @cfg {String} align left | right - for navbars
6112 * @param {Object} config The config object
6116 Roo.bootstrap.Form = function(config){
6117 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6120 * @event clientvalidation
6121 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6122 * @param {Form} this
6123 * @param {Boolean} valid true if the form has passed client-side validation
6125 clientvalidation: true,
6127 * @event beforeaction
6128 * Fires before any action is performed. Return false to cancel the action.
6129 * @param {Form} this
6130 * @param {Action} action The action to be performed
6134 * @event actionfailed
6135 * Fires when an action fails.
6136 * @param {Form} this
6137 * @param {Action} action The action that failed
6139 actionfailed : true,
6141 * @event actioncomplete
6142 * Fires when an action is completed.
6143 * @param {Form} this
6144 * @param {Action} action The action that completed
6146 actioncomplete : true
6151 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6154 * @cfg {String} method
6155 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6160 * The URL to use for form actions if one isn't supplied in the action options.
6163 * @cfg {Boolean} fileUpload
6164 * Set to true if this form is a file upload.
6168 * @cfg {Object} baseParams
6169 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6173 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6177 * @cfg {Sting} align (left|right) for navbar forms
6182 activeAction : null,
6185 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6186 * element by passing it or its id or mask the form itself by passing in true.
6189 waitMsgTarget : false,
6194 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6195 * element by passing it or its id or mask the form itself by passing in true.
6199 getAutoCreate : function(){
6203 method : this.method || 'POST',
6204 id : this.id || Roo.id(),
6207 if (this.parent().xtype.match(/^Nav/)) {
6208 cfg.cls = 'navbar-form navbar-' + this.align;
6212 if (this.labelAlign == 'left' ) {
6213 cfg.cls += ' form-horizontal';
6219 initEvents : function()
6221 this.el.on('submit', this.onSubmit, this);
6222 // this was added as random key presses on the form where triggering form submit.
6223 this.el.on('keypress', function(e) {
6224 if (e.getCharCode() != 13) {
6227 // we might need to allow it for textareas.. and some other items.
6228 // check e.getTarget().
6230 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6234 Roo.log("keypress blocked");
6242 onSubmit : function(e){
6247 * Returns true if client-side validation on the form is successful.
6250 isValid : function(){
6251 var items = this.getItems();
6253 items.each(function(f){
6262 * Returns true if any fields in this form have changed since their original load.
6265 isDirty : function(){
6267 var items = this.getItems();
6268 items.each(function(f){
6278 * Performs a predefined action (submit or load) or custom actions you define on this form.
6279 * @param {String} actionName The name of the action type
6280 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6281 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6282 * accept other config options):
6284 Property Type Description
6285 ---------------- --------------- ----------------------------------------------------------------------------------
6286 url String The url for the action (defaults to the form's url)
6287 method String The form method to use (defaults to the form's method, or POST if not defined)
6288 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6289 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6290 validate the form on the client (defaults to false)
6292 * @return {BasicForm} this
6294 doAction : function(action, options){
6295 if(typeof action == 'string'){
6296 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6298 if(this.fireEvent('beforeaction', this, action) !== false){
6299 this.beforeAction(action);
6300 action.run.defer(100, action);
6306 beforeAction : function(action){
6307 var o = action.options;
6309 // not really supported yet.. ??
6311 //if(this.waitMsgTarget === true){
6312 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6313 //}else if(this.waitMsgTarget){
6314 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6315 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6317 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6323 afterAction : function(action, success){
6324 this.activeAction = null;
6325 var o = action.options;
6327 //if(this.waitMsgTarget === true){
6329 //}else if(this.waitMsgTarget){
6330 // this.waitMsgTarget.unmask();
6332 // Roo.MessageBox.updateProgress(1);
6333 // Roo.MessageBox.hide();
6340 Roo.callback(o.success, o.scope, [this, action]);
6341 this.fireEvent('actioncomplete', this, action);
6345 // failure condition..
6346 // we have a scenario where updates need confirming.
6347 // eg. if a locking scenario exists..
6348 // we look for { errors : { needs_confirm : true }} in the response.
6350 (typeof(action.result) != 'undefined') &&
6351 (typeof(action.result.errors) != 'undefined') &&
6352 (typeof(action.result.errors.needs_confirm) != 'undefined')
6355 Roo.log("not supported yet");
6358 Roo.MessageBox.confirm(
6359 "Change requires confirmation",
6360 action.result.errorMsg,
6365 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6375 Roo.callback(o.failure, o.scope, [this, action]);
6376 // show an error message if no failed handler is set..
6377 if (!this.hasListener('actionfailed')) {
6378 Roo.log("need to add dialog support");
6380 Roo.MessageBox.alert("Error",
6381 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6382 action.result.errorMsg :
6383 "Saving Failed, please check your entries or try again"
6388 this.fireEvent('actionfailed', this, action);
6393 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6394 * @param {String} id The value to search for
6397 findField : function(id){
6398 var items = this.getItems();
6399 var field = items.get(id);
6401 items.each(function(f){
6402 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6409 return field || null;
6412 * Mark fields in this form invalid in bulk.
6413 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6414 * @return {BasicForm} this
6416 markInvalid : function(errors){
6417 if(errors instanceof Array){
6418 for(var i = 0, len = errors.length; i < len; i++){
6419 var fieldError = errors[i];
6420 var f = this.findField(fieldError.id);
6422 f.markInvalid(fieldError.msg);
6428 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6429 field.markInvalid(errors[id]);
6433 //Roo.each(this.childForms || [], function (f) {
6434 // f.markInvalid(errors);
6441 * Set values for fields in this form in bulk.
6442 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6443 * @return {BasicForm} this
6445 setValues : function(values){
6446 if(values instanceof Array){ // array of objects
6447 for(var i = 0, len = values.length; i < len; i++){
6449 var f = this.findField(v.id);
6451 f.setValue(v.value);
6452 if(this.trackResetOnLoad){
6453 f.originalValue = f.getValue();
6457 }else{ // object hash
6460 if(typeof values[id] != 'function' && (field = this.findField(id))){
6462 if (field.setFromData &&
6464 field.displayField &&
6465 // combos' with local stores can
6466 // be queried via setValue()
6467 // to set their value..
6468 (field.store && !field.store.isLocal)
6472 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6473 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6474 field.setFromData(sd);
6477 field.setValue(values[id]);
6481 if(this.trackResetOnLoad){
6482 field.originalValue = field.getValue();
6488 //Roo.each(this.childForms || [], function (f) {
6489 // f.setValues(values);
6496 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6497 * they are returned as an array.
6498 * @param {Boolean} asString
6501 getValues : function(asString){
6502 //if (this.childForms) {
6503 // copy values from the child forms
6504 // Roo.each(this.childForms, function (f) {
6505 // this.setValues(f.getValues());
6511 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6512 if(asString === true){
6515 return Roo.urlDecode(fs);
6519 * Returns the fields in this form as an object with key/value pairs.
6520 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6523 getFieldValues : function(with_hidden)
6525 var items = this.getItems();
6527 items.each(function(f){
6531 var v = f.getValue();
6532 if (f.inputType =='radio') {
6533 if (typeof(ret[f.getName()]) == 'undefined') {
6534 ret[f.getName()] = ''; // empty..
6537 if (!f.el.dom.checked) {
6545 // not sure if this supported any more..
6546 if ((typeof(v) == 'object') && f.getRawValue) {
6547 v = f.getRawValue() ; // dates..
6549 // combo boxes where name != hiddenName...
6550 if (f.name != f.getName()) {
6551 ret[f.name] = f.getRawValue();
6553 ret[f.getName()] = v;
6560 * Clears all invalid messages in this form.
6561 * @return {BasicForm} this
6563 clearInvalid : function(){
6564 var items = this.getItems();
6566 items.each(function(f){
6577 * @return {BasicForm} this
6580 var items = this.getItems();
6581 items.each(function(f){
6585 Roo.each(this.childForms || [], function (f) {
6592 getItems : function()
6594 var r=new Roo.util.MixedCollection(false, function(o){
6595 return o.id || (o.id = Roo.id());
6597 var iter = function(el) {
6604 Roo.each(el.items,function(e) {
6623 * Ext JS Library 1.1.1
6624 * Copyright(c) 2006-2007, Ext JS, LLC.
6626 * Originally Released Under LGPL - original licence link has changed is not relivant.
6629 * <script type="text/javascript">
6632 * @class Roo.form.VTypes
6633 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6636 Roo.form.VTypes = function(){
6637 // closure these in so they are only created once.
6638 var alpha = /^[a-zA-Z_]+$/;
6639 var alphanum = /^[a-zA-Z0-9_]+$/;
6640 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6641 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6643 // All these messages and functions are configurable
6646 * The function used to validate email addresses
6647 * @param {String} value The email address
6649 'email' : function(v){
6650 return email.test(v);
6653 * The error text to display when the email validation function returns false
6656 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6658 * The keystroke filter mask to be applied on email input
6661 'emailMask' : /[a-z0-9_\.\-@]/i,
6664 * The function used to validate URLs
6665 * @param {String} value The URL
6667 'url' : function(v){
6671 * The error text to display when the url validation function returns false
6674 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6677 * The function used to validate alpha values
6678 * @param {String} value The value
6680 'alpha' : function(v){
6681 return alpha.test(v);
6684 * The error text to display when the alpha validation function returns false
6687 'alphaText' : 'This field should only contain letters and _',
6689 * The keystroke filter mask to be applied on alpha input
6692 'alphaMask' : /[a-z_]/i,
6695 * The function used to validate alphanumeric values
6696 * @param {String} value The value
6698 'alphanum' : function(v){
6699 return alphanum.test(v);
6702 * The error text to display when the alphanumeric validation function returns false
6705 'alphanumText' : 'This field should only contain letters, numbers and _',
6707 * The keystroke filter mask to be applied on alphanumeric input
6710 'alphanumMask' : /[a-z0-9_]/i
6720 * @class Roo.bootstrap.Input
6721 * @extends Roo.bootstrap.Component
6722 * Bootstrap Input class
6723 * @cfg {Boolean} disabled is it disabled
6724 * @cfg {String} fieldLabel - the label associated
6725 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6726 * @cfg {String} name name of the input
6727 * @cfg {string} fieldLabel - the label associated
6728 * @cfg {string} inputType - input / file submit ...
6729 * @cfg {string} placeholder - placeholder to put in text.
6730 * @cfg {string} before - input group add on before
6731 * @cfg {string} after - input group add on after
6732 * @cfg {string} size - (lg|sm) or leave empty..
6733 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6734 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6735 * @cfg {Number} md colspan out of 12 for computer-sized screens
6736 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6737 * @cfg {string} value default value of the input
6738 * @cfg {Number} labelWidth set the width of label (0-12)
6739 * @cfg {String} labelAlign (top|left)
6740 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6741 * @cfg {String} align (left|center|right) Default left
6745 * Create a new Input
6746 * @param {Object} config The config object
6749 Roo.bootstrap.Input = function(config){
6750 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6755 * Fires when this field receives input focus.
6756 * @param {Roo.form.Field} this
6761 * Fires when this field loses input focus.
6762 * @param {Roo.form.Field} this
6767 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6768 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6769 * @param {Roo.form.Field} this
6770 * @param {Roo.EventObject} e The event object
6775 * Fires just before the field blurs if the field value has changed.
6776 * @param {Roo.form.Field} this
6777 * @param {Mixed} newValue The new value
6778 * @param {Mixed} oldValue The original value
6783 * Fires after the field has been marked as invalid.
6784 * @param {Roo.form.Field} this
6785 * @param {String} msg The validation message
6790 * Fires after the field has been validated with no errors.
6791 * @param {Roo.form.Field} this
6796 * Fires after the key up
6797 * @param {Roo.form.Field} this
6798 * @param {Roo.EventObject} e The event Object
6804 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6806 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6807 automatic validation (defaults to "keyup").
6809 validationEvent : "keyup",
6811 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6813 validateOnBlur : true,
6815 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6817 validationDelay : 250,
6819 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6821 focusClass : "x-form-focus", // not needed???
6825 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6827 invalidClass : "has-error",
6830 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6832 selectOnFocus : false,
6835 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6839 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6844 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6846 disableKeyFilter : false,
6849 * @cfg {Boolean} disabled True to disable the field (defaults to false).
6853 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6857 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6859 blankText : "This field is required",
6862 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
6866 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
6868 maxLength : Number.MAX_VALUE,
6870 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
6872 minLengthText : "The minimum length for this field is {0}",
6874 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
6876 maxLengthText : "The maximum length for this field is {0}",
6880 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
6881 * If available, this function will be called only after the basic validators all return true, and will be passed the
6882 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
6886 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
6887 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
6888 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
6892 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
6915 formatedValue : false,
6917 parentLabelAlign : function()
6920 while (parent.parent()) {
6921 parent = parent.parent();
6922 if (typeof(parent.labelAlign) !='undefined') {
6923 return parent.labelAlign;
6930 getAutoCreate : function(){
6932 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6938 if(this.inputType != 'hidden'){
6939 cfg.cls = 'form-group' //input-group
6945 type : this.inputType,
6947 cls : 'form-control',
6948 placeholder : this.placeholder || ''
6953 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
6956 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6957 input.maxLength = this.maxLength;
6960 if (this.disabled) {
6961 input.disabled=true;
6964 if (this.readOnly) {
6965 input.readonly=true;
6969 input.name = this.name;
6972 input.cls += ' input-' + this.size;
6975 ['xs','sm','md','lg'].map(function(size){
6976 if (settings[size]) {
6977 cfg.cls += ' col-' + size + '-' + settings[size];
6981 var inputblock = input;
6983 if (this.before || this.after) {
6986 cls : 'input-group',
6989 if (this.before && typeof(this.before) == 'string') {
6991 inputblock.cn.push({
6993 cls : 'roo-input-before input-group-addon',
6997 if (this.before && typeof(this.before) == 'object') {
6998 this.before = Roo.factory(this.before);
6999 Roo.log(this.before);
7000 inputblock.cn.push({
7002 cls : 'roo-input-before input-group-' +
7003 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7007 inputblock.cn.push(input);
7009 if (this.after && typeof(this.after) == 'string') {
7010 inputblock.cn.push({
7012 cls : 'roo-input-after input-group-addon',
7016 if (this.after && typeof(this.after) == 'object') {
7017 this.after = Roo.factory(this.after);
7018 Roo.log(this.after);
7019 inputblock.cn.push({
7021 cls : 'roo-input-after input-group-' +
7022 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7027 if (align ==='left' && this.fieldLabel.length) {
7028 Roo.log("left and has label");
7034 cls : 'control-label col-sm-' + this.labelWidth,
7035 html : this.fieldLabel
7039 cls : "col-sm-" + (12 - this.labelWidth),
7046 } else if ( this.fieldLabel.length) {
7052 //cls : 'input-group-addon',
7053 html : this.fieldLabel
7063 Roo.log(" no label && no align");
7072 Roo.log('input-parentType: ' + this.parentType);
7074 if (this.parentType === 'Navbar' && this.parent().bar) {
7075 cfg.cls += ' navbar-form';
7083 * return the real input element.
7085 inputEl: function ()
7087 return this.el.select('input.form-control',true).first();
7089 setDisabled : function(v)
7091 var i = this.inputEl().dom;
7093 i.removeAttribute('disabled');
7097 i.setAttribute('disabled','true');
7099 initEvents : function()
7102 this.inputEl().on("keydown" , this.fireKey, this);
7103 this.inputEl().on("focus", this.onFocus, this);
7104 this.inputEl().on("blur", this.onBlur, this);
7106 this.inputEl().relayEvent('keyup', this);
7108 // reference to original value for reset
7109 this.originalValue = this.getValue();
7110 //Roo.form.TextField.superclass.initEvents.call(this);
7111 if(this.validationEvent == 'keyup'){
7112 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7113 this.inputEl().on('keyup', this.filterValidation, this);
7115 else if(this.validationEvent !== false){
7116 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7119 if(this.selectOnFocus){
7120 this.on("focus", this.preFocus, this);
7123 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7124 this.inputEl().on("keypress", this.filterKeys, this);
7127 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7128 this.el.on("click", this.autoSize, this);
7131 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7132 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7135 if (typeof(this.before) == 'object') {
7136 this.before.render(this.el.select('.roo-input-before',true).first());
7138 if (typeof(this.after) == 'object') {
7139 this.after.render(this.el.select('.roo-input-after',true).first());
7144 filterValidation : function(e){
7145 if(!e.isNavKeyPress()){
7146 this.validationTask.delay(this.validationDelay);
7150 * Validates the field value
7151 * @return {Boolean} True if the value is valid, else false
7153 validate : function(){
7154 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7155 if(this.disabled || this.validateValue(this.getRawValue())){
7156 this.clearInvalid();
7164 * Validates a value according to the field's validation rules and marks the field as invalid
7165 * if the validation fails
7166 * @param {Mixed} value The value to validate
7167 * @return {Boolean} True if the value is valid, else false
7169 validateValue : function(value){
7170 if(value.length < 1) { // if it's blank
7171 if(this.allowBlank){
7172 this.clearInvalid();
7175 this.markInvalid(this.blankText);
7179 if(value.length < this.minLength){
7180 this.markInvalid(String.format(this.minLengthText, this.minLength));
7183 if(value.length > this.maxLength){
7184 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
7188 var vt = Roo.form.VTypes;
7189 if(!vt[this.vtype](value, this)){
7190 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
7194 if(typeof this.validator == "function"){
7195 var msg = this.validator(value);
7197 this.markInvalid(msg);
7201 if(this.regex && !this.regex.test(value)){
7202 this.markInvalid(this.regexText);
7211 fireKey : function(e){
7212 //Roo.log('field ' + e.getKey());
7213 if(e.isNavKeyPress()){
7214 this.fireEvent("specialkey", this, e);
7217 focus : function (selectText){
7219 this.inputEl().focus();
7220 if(selectText === true){
7221 this.inputEl().dom.select();
7227 onFocus : function(){
7228 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7229 // this.el.addClass(this.focusClass);
7232 this.hasFocus = true;
7233 this.startValue = this.getValue();
7234 this.fireEvent("focus", this);
7238 beforeBlur : Roo.emptyFn,
7242 onBlur : function(){
7244 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7245 //this.el.removeClass(this.focusClass);
7247 this.hasFocus = false;
7248 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7251 var v = this.getValue();
7252 if(String(v) !== String(this.startValue)){
7253 this.fireEvent('change', this, v, this.startValue);
7255 this.fireEvent("blur", this);
7259 * Resets the current field value to the originally loaded value and clears any validation messages
7262 this.setValue(this.originalValue);
7263 this.clearInvalid();
7266 * Returns the name of the field
7267 * @return {Mixed} name The name field
7269 getName: function(){
7273 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7274 * @return {Mixed} value The field value
7276 getValue : function(){
7278 var v = this.inputEl().getValue();
7283 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7284 * @return {Mixed} value The field value
7286 getRawValue : function(){
7287 var v = this.inputEl().getValue();
7293 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7294 * @param {Mixed} value The value to set
7296 setRawValue : function(v){
7297 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7300 selectText : function(start, end){
7301 var v = this.getRawValue();
7303 start = start === undefined ? 0 : start;
7304 end = end === undefined ? v.length : end;
7305 var d = this.inputEl().dom;
7306 if(d.setSelectionRange){
7307 d.setSelectionRange(start, end);
7308 }else if(d.createTextRange){
7309 var range = d.createTextRange();
7310 range.moveStart("character", start);
7311 range.moveEnd("character", v.length-end);
7318 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7319 * @param {Mixed} value The value to set
7321 setValue : function(v){
7324 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7330 processValue : function(value){
7331 if(this.stripCharsRe){
7332 var newValue = value.replace(this.stripCharsRe, '');
7333 if(newValue !== value){
7334 this.setRawValue(newValue);
7341 preFocus : function(){
7343 if(this.selectOnFocus){
7344 this.inputEl().dom.select();
7347 filterKeys : function(e){
7349 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7352 var c = e.getCharCode(), cc = String.fromCharCode(c);
7353 if(Roo.isIE && (e.isSpecialKey() || !cc)){
7356 if(!this.maskRe.test(cc)){
7361 * Clear any invalid styles/messages for this field
7363 clearInvalid : function(){
7365 if(!this.el || this.preventMark){ // not rendered
7368 this.el.removeClass(this.invalidClass);
7370 switch(this.msgTarget){
7372 this.el.dom.qtip = '';
7375 this.el.dom.title = '';
7379 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7384 this.errorIcon.dom.qtip = '';
7385 this.errorIcon.hide();
7386 this.un('resize', this.alignErrorIcon, this);
7390 var t = Roo.getDom(this.msgTarget);
7392 t.style.display = 'none';
7396 this.fireEvent('valid', this);
7399 * Mark this field as invalid
7400 * @param {String} msg The validation message
7402 markInvalid : function(msg){
7403 if(!this.el || this.preventMark){ // not rendered
7406 this.el.addClass(this.invalidClass);
7408 msg = msg || this.invalidText;
7409 switch(this.msgTarget){
7411 this.el.dom.qtip = msg;
7412 this.el.dom.qclass = 'x-form-invalid-tip';
7413 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7414 Roo.QuickTips.enable();
7418 this.el.dom.title = msg;
7422 var elp = this.el.findParent('.x-form-element', 5, true);
7423 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7424 this.errorEl.setWidth(elp.getWidth(true)-20);
7426 this.errorEl.update(msg);
7427 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7430 if(!this.errorIcon){
7431 var elp = this.el.findParent('.x-form-element', 5, true);
7432 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7434 this.alignErrorIcon();
7435 this.errorIcon.dom.qtip = msg;
7436 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7437 this.errorIcon.show();
7438 this.on('resize', this.alignErrorIcon, this);
7441 var t = Roo.getDom(this.msgTarget);
7443 t.style.display = this.msgDisplay;
7447 this.fireEvent('invalid', this, msg);
7450 SafariOnKeyDown : function(event)
7452 // this is a workaround for a password hang bug on chrome/ webkit.
7454 var isSelectAll = false;
7456 if(this.inputEl().dom.selectionEnd > 0){
7457 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7459 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7460 event.preventDefault();
7465 if(isSelectAll){ // backspace and delete key
7467 event.preventDefault();
7468 // this is very hacky as keydown always get's upper case.
7470 var cc = String.fromCharCode(event.getCharCode());
7471 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7475 adjustWidth : function(tag, w){
7476 tag = tag.toLowerCase();
7477 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7478 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7482 if(tag == 'textarea'){
7485 }else if(Roo.isOpera){
7489 if(tag == 'textarea'){
7508 * @class Roo.bootstrap.TextArea
7509 * @extends Roo.bootstrap.Input
7510 * Bootstrap TextArea class
7511 * @cfg {Number} cols Specifies the visible width of a text area
7512 * @cfg {Number} rows Specifies the visible number of lines in a text area
7513 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7514 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7515 * @cfg {string} html text
7518 * Create a new TextArea
7519 * @param {Object} config The config object
7522 Roo.bootstrap.TextArea = function(config){
7523 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7527 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7537 getAutoCreate : function(){
7539 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7550 value : this.value || '',
7551 html: this.html || '',
7552 cls : 'form-control',
7553 placeholder : this.placeholder || ''
7557 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7558 input.maxLength = this.maxLength;
7562 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7566 input.cols = this.cols;
7569 if (this.readOnly) {
7570 input.readonly = true;
7574 input.name = this.name;
7578 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7582 ['xs','sm','md','lg'].map(function(size){
7583 if (settings[size]) {
7584 cfg.cls += ' col-' + size + '-' + settings[size];
7588 var inputblock = input;
7590 if (this.before || this.after) {
7593 cls : 'input-group',
7597 inputblock.cn.push({
7599 cls : 'input-group-addon',
7603 inputblock.cn.push(input);
7605 inputblock.cn.push({
7607 cls : 'input-group-addon',
7614 if (align ==='left' && this.fieldLabel.length) {
7615 Roo.log("left and has label");
7621 cls : 'control-label col-sm-' + this.labelWidth,
7622 html : this.fieldLabel
7626 cls : "col-sm-" + (12 - this.labelWidth),
7633 } else if ( this.fieldLabel.length) {
7639 //cls : 'input-group-addon',
7640 html : this.fieldLabel
7650 Roo.log(" no label && no align");
7660 if (this.disabled) {
7661 input.disabled=true;
7668 * return the real textarea element.
7670 inputEl: function ()
7672 return this.el.select('textarea.form-control',true).first();
7680 * trigger field - base class for combo..
7685 * @class Roo.bootstrap.TriggerField
7686 * @extends Roo.bootstrap.Input
7687 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7688 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7689 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7690 * for which you can provide a custom implementation. For example:
7692 var trigger = new Roo.bootstrap.TriggerField();
7693 trigger.onTriggerClick = myTriggerFn;
7694 trigger.applyTo('my-field');
7697 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7698 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7699 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7700 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7702 * Create a new TriggerField.
7703 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7704 * to the base TextField)
7706 Roo.bootstrap.TriggerField = function(config){
7707 this.mimicing = false;
7708 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7711 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7713 * @cfg {String} triggerClass A CSS class to apply to the trigger
7716 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7720 /** @cfg {Boolean} grow @hide */
7721 /** @cfg {Number} growMin @hide */
7722 /** @cfg {Number} growMax @hide */
7728 autoSize: Roo.emptyFn,
7735 actionMode : 'wrap',
7739 getAutoCreate : function(){
7741 var align = this.labelAlign || this.parentLabelAlign();
7746 cls: 'form-group' //input-group
7753 type : this.inputType,
7754 cls : 'form-control',
7755 autocomplete: 'off',
7756 placeholder : this.placeholder || ''
7760 input.name = this.name;
7763 input.cls += ' input-' + this.size;
7766 if (this.disabled) {
7767 input.disabled=true;
7770 var inputblock = input;
7772 if (this.before || this.after) {
7775 cls : 'input-group',
7779 inputblock.cn.push({
7781 cls : 'input-group-addon',
7785 inputblock.cn.push(input);
7787 inputblock.cn.push({
7789 cls : 'input-group-addon',
7802 cls: 'form-hidden-field'
7810 Roo.log('multiple');
7818 cls: 'form-hidden-field'
7822 cls: 'select2-choices',
7826 cls: 'select2-search-field',
7839 cls: 'select2-container input-group',
7844 // cls: 'typeahead typeahead-long dropdown-menu',
7845 // style: 'display:none'
7850 if(!this.multiple && this.showToggleBtn){
7853 cls : 'input-group-addon btn dropdown-toggle',
7861 cls: 'combobox-clear',
7875 combobox.cls += ' select2-container-multi';
7878 if (align ==='left' && this.fieldLabel.length) {
7880 Roo.log("left and has label");
7886 cls : 'control-label col-sm-' + this.labelWidth,
7887 html : this.fieldLabel
7891 cls : "col-sm-" + (12 - this.labelWidth),
7898 } else if ( this.fieldLabel.length) {
7904 //cls : 'input-group-addon',
7905 html : this.fieldLabel
7915 Roo.log(" no label && no align");
7922 ['xs','sm','md','lg'].map(function(size){
7923 if (settings[size]) {
7924 cfg.cls += ' col-' + size + '-' + settings[size];
7935 onResize : function(w, h){
7936 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
7937 // if(typeof w == 'number'){
7938 // var x = w - this.trigger.getWidth();
7939 // this.inputEl().setWidth(this.adjustWidth('input', x));
7940 // this.trigger.setStyle('left', x+'px');
7945 adjustSize : Roo.BoxComponent.prototype.adjustSize,
7948 getResizeEl : function(){
7949 return this.inputEl();
7953 getPositionEl : function(){
7954 return this.inputEl();
7958 alignErrorIcon : function(){
7959 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
7963 initEvents : function(){
7967 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
7968 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
7969 if(!this.multiple && this.showToggleBtn){
7970 this.trigger = this.el.select('span.dropdown-toggle',true).first();
7971 if(this.hideTrigger){
7972 this.trigger.setDisplayed(false);
7974 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
7978 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
7981 //this.trigger.addClassOnOver('x-form-trigger-over');
7982 //this.trigger.addClassOnClick('x-form-trigger-click');
7985 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
7989 createList : function()
7991 this.list = Roo.get(document.body).createChild({
7993 cls: 'typeahead typeahead-long dropdown-menu',
7994 style: 'display:none'
7997 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8002 initTrigger : function(){
8007 onDestroy : function(){
8009 this.trigger.removeAllListeners();
8010 // this.trigger.remove();
8013 // this.wrap.remove();
8015 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8019 onFocus : function(){
8020 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8023 this.wrap.addClass('x-trigger-wrap-focus');
8024 this.mimicing = true;
8025 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8026 if(this.monitorTab){
8027 this.el.on("keydown", this.checkTab, this);
8034 checkTab : function(e){
8035 if(e.getKey() == e.TAB){
8041 onBlur : function(){
8046 mimicBlur : function(e, t){
8048 if(!this.wrap.contains(t) && this.validateBlur()){
8055 triggerBlur : function(){
8056 this.mimicing = false;
8057 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8058 if(this.monitorTab){
8059 this.el.un("keydown", this.checkTab, this);
8061 //this.wrap.removeClass('x-trigger-wrap-focus');
8062 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8066 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8067 validateBlur : function(e, t){
8072 onDisable : function(){
8073 this.inputEl().dom.disabled = true;
8074 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8076 // this.wrap.addClass('x-item-disabled');
8081 onEnable : function(){
8082 this.inputEl().dom.disabled = false;
8083 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8085 // this.el.removeClass('x-item-disabled');
8090 onShow : function(){
8091 var ae = this.getActionEl();
8094 ae.dom.style.display = '';
8095 ae.dom.style.visibility = 'visible';
8101 onHide : function(){
8102 var ae = this.getActionEl();
8103 ae.dom.style.display = 'none';
8107 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8108 * by an implementing function.
8110 * @param {EventObject} e
8112 onTriggerClick : Roo.emptyFn
8116 * Ext JS Library 1.1.1
8117 * Copyright(c) 2006-2007, Ext JS, LLC.
8119 * Originally Released Under LGPL - original licence link has changed is not relivant.
8122 * <script type="text/javascript">
8127 * @class Roo.data.SortTypes
8129 * Defines the default sorting (casting?) comparison functions used when sorting data.
8131 Roo.data.SortTypes = {
8133 * Default sort that does nothing
8134 * @param {Mixed} s The value being converted
8135 * @return {Mixed} The comparison value
8142 * The regular expression used to strip tags
8146 stripTagsRE : /<\/?[^>]+>/gi,
8149 * Strips all HTML tags to sort on text only
8150 * @param {Mixed} s The value being converted
8151 * @return {String} The comparison value
8153 asText : function(s){
8154 return String(s).replace(this.stripTagsRE, "");
8158 * Strips all HTML tags to sort on text only - Case insensitive
8159 * @param {Mixed} s The value being converted
8160 * @return {String} The comparison value
8162 asUCText : function(s){
8163 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8167 * Case insensitive string
8168 * @param {Mixed} s The value being converted
8169 * @return {String} The comparison value
8171 asUCString : function(s) {
8172 return String(s).toUpperCase();
8177 * @param {Mixed} s The value being converted
8178 * @return {Number} The comparison value
8180 asDate : function(s) {
8184 if(s instanceof Date){
8187 return Date.parse(String(s));
8192 * @param {Mixed} s The value being converted
8193 * @return {Float} The comparison value
8195 asFloat : function(s) {
8196 var val = parseFloat(String(s).replace(/,/g, ""));
8197 if(isNaN(val)) val = 0;
8203 * @param {Mixed} s The value being converted
8204 * @return {Number} The comparison value
8206 asInt : function(s) {
8207 var val = parseInt(String(s).replace(/,/g, ""));
8208 if(isNaN(val)) val = 0;
8213 * Ext JS Library 1.1.1
8214 * Copyright(c) 2006-2007, Ext JS, LLC.
8216 * Originally Released Under LGPL - original licence link has changed is not relivant.
8219 * <script type="text/javascript">
8223 * @class Roo.data.Record
8224 * Instances of this class encapsulate both record <em>definition</em> information, and record
8225 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8226 * to access Records cached in an {@link Roo.data.Store} object.<br>
8228 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8229 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8232 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8234 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8235 * {@link #create}. The parameters are the same.
8236 * @param {Array} data An associative Array of data values keyed by the field name.
8237 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8238 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8239 * not specified an integer id is generated.
8241 Roo.data.Record = function(data, id){
8242 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8247 * Generate a constructor for a specific record layout.
8248 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8249 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8250 * Each field definition object may contain the following properties: <ul>
8251 * <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,
8252 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8253 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8254 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8255 * is being used, then this is a string containing the javascript expression to reference the data relative to
8256 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8257 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8258 * this may be omitted.</p></li>
8259 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8260 * <ul><li>auto (Default, implies no conversion)</li>
8265 * <li>date</li></ul></p></li>
8266 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8267 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8268 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8269 * by the Reader into an object that will be stored in the Record. It is passed the
8270 * following parameters:<ul>
8271 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8273 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8275 * <br>usage:<br><pre><code>
8276 var TopicRecord = Roo.data.Record.create(
8277 {name: 'title', mapping: 'topic_title'},
8278 {name: 'author', mapping: 'username'},
8279 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8280 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8281 {name: 'lastPoster', mapping: 'user2'},
8282 {name: 'excerpt', mapping: 'post_text'}
8285 var myNewRecord = new TopicRecord({
8286 title: 'Do my job please',
8289 lastPost: new Date(),
8290 lastPoster: 'Animal',
8291 excerpt: 'No way dude!'
8293 myStore.add(myNewRecord);
8298 Roo.data.Record.create = function(o){
8300 f.superclass.constructor.apply(this, arguments);
8302 Roo.extend(f, Roo.data.Record);
8303 var p = f.prototype;
8304 p.fields = new Roo.util.MixedCollection(false, function(field){
8307 for(var i = 0, len = o.length; i < len; i++){
8308 p.fields.add(new Roo.data.Field(o[i]));
8310 f.getField = function(name){
8311 return p.fields.get(name);
8316 Roo.data.Record.AUTO_ID = 1000;
8317 Roo.data.Record.EDIT = 'edit';
8318 Roo.data.Record.REJECT = 'reject';
8319 Roo.data.Record.COMMIT = 'commit';
8321 Roo.data.Record.prototype = {
8323 * Readonly flag - true if this record has been modified.
8332 join : function(store){
8337 * Set the named field to the specified value.
8338 * @param {String} name The name of the field to set.
8339 * @param {Object} value The value to set the field to.
8341 set : function(name, value){
8342 if(this.data[name] == value){
8349 if(typeof this.modified[name] == 'undefined'){
8350 this.modified[name] = this.data[name];
8352 this.data[name] = value;
8353 if(!this.editing && this.store){
8354 this.store.afterEdit(this);
8359 * Get the value of the named field.
8360 * @param {String} name The name of the field to get the value of.
8361 * @return {Object} The value of the field.
8363 get : function(name){
8364 return this.data[name];
8368 beginEdit : function(){
8369 this.editing = true;
8374 cancelEdit : function(){
8375 this.editing = false;
8376 delete this.modified;
8380 endEdit : function(){
8381 this.editing = false;
8382 if(this.dirty && this.store){
8383 this.store.afterEdit(this);
8388 * Usually called by the {@link Roo.data.Store} which owns the Record.
8389 * Rejects all changes made to the Record since either creation, or the last commit operation.
8390 * Modified fields are reverted to their original values.
8392 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8393 * of reject operations.
8395 reject : function(){
8396 var m = this.modified;
8398 if(typeof m[n] != "function"){
8399 this.data[n] = m[n];
8403 delete this.modified;
8404 this.editing = false;
8406 this.store.afterReject(this);
8411 * Usually called by the {@link Roo.data.Store} which owns the Record.
8412 * Commits all changes made to the Record since either creation, or the last commit operation.
8414 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8415 * of commit operations.
8417 commit : function(){
8419 delete this.modified;
8420 this.editing = false;
8422 this.store.afterCommit(this);
8427 hasError : function(){
8428 return this.error != null;
8432 clearError : function(){
8437 * Creates a copy of this record.
8438 * @param {String} id (optional) A new record id if you don't want to use this record's id
8441 copy : function(newId) {
8442 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8446 * Ext JS Library 1.1.1
8447 * Copyright(c) 2006-2007, Ext JS, LLC.
8449 * Originally Released Under LGPL - original licence link has changed is not relivant.
8452 * <script type="text/javascript">
8458 * @class Roo.data.Store
8459 * @extends Roo.util.Observable
8460 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8461 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8463 * 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
8464 * has no knowledge of the format of the data returned by the Proxy.<br>
8466 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8467 * instances from the data object. These records are cached and made available through accessor functions.
8469 * Creates a new Store.
8470 * @param {Object} config A config object containing the objects needed for the Store to access data,
8471 * and read the data into Records.
8473 Roo.data.Store = function(config){
8474 this.data = new Roo.util.MixedCollection(false);
8475 this.data.getKey = function(o){
8478 this.baseParams = {};
8485 "multisort" : "_multisort"
8488 if(config && config.data){
8489 this.inlineData = config.data;
8493 Roo.apply(this, config);
8495 if(this.reader){ // reader passed
8496 this.reader = Roo.factory(this.reader, Roo.data);
8497 this.reader.xmodule = this.xmodule || false;
8498 if(!this.recordType){
8499 this.recordType = this.reader.recordType;
8501 if(this.reader.onMetaChange){
8502 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8506 if(this.recordType){
8507 this.fields = this.recordType.prototype.fields;
8513 * @event datachanged
8514 * Fires when the data cache has changed, and a widget which is using this Store
8515 * as a Record cache should refresh its view.
8516 * @param {Store} this
8521 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8522 * @param {Store} this
8523 * @param {Object} meta The JSON metadata
8528 * Fires when Records have been added to the Store
8529 * @param {Store} this
8530 * @param {Roo.data.Record[]} records The array of Records added
8531 * @param {Number} index The index at which the record(s) were added
8536 * Fires when a Record has been removed from the Store
8537 * @param {Store} this
8538 * @param {Roo.data.Record} record The Record that was removed
8539 * @param {Number} index The index at which the record was removed
8544 * Fires when a Record has been updated
8545 * @param {Store} this
8546 * @param {Roo.data.Record} record The Record that was updated
8547 * @param {String} operation The update operation being performed. Value may be one of:
8549 Roo.data.Record.EDIT
8550 Roo.data.Record.REJECT
8551 Roo.data.Record.COMMIT
8557 * Fires when the data cache has been cleared.
8558 * @param {Store} this
8563 * Fires before a request is made for a new data object. If the beforeload handler returns false
8564 * the load action will be canceled.
8565 * @param {Store} this
8566 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8570 * @event beforeloadadd
8571 * Fires after a new set of Records has been loaded.
8572 * @param {Store} this
8573 * @param {Roo.data.Record[]} records The Records that were loaded
8574 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8576 beforeloadadd : true,
8579 * Fires after a new set of Records has been loaded, before they are added to the store.
8580 * @param {Store} this
8581 * @param {Roo.data.Record[]} records The Records that were loaded
8582 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8583 * @params {Object} return from reader
8587 * @event loadexception
8588 * Fires if an exception occurs in the Proxy during loading.
8589 * Called with the signature of the Proxy's "loadexception" event.
8590 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8593 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8594 * @param {Object} load options
8595 * @param {Object} jsonData from your request (normally this contains the Exception)
8597 loadexception : true
8601 this.proxy = Roo.factory(this.proxy, Roo.data);
8602 this.proxy.xmodule = this.xmodule || false;
8603 this.relayEvents(this.proxy, ["loadexception"]);
8605 this.sortToggle = {};
8606 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8608 Roo.data.Store.superclass.constructor.call(this);
8610 if(this.inlineData){
8611 this.loadData(this.inlineData);
8612 delete this.inlineData;
8616 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8618 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8619 * without a remote query - used by combo/forms at present.
8623 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8626 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8629 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8630 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8633 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8634 * on any HTTP request
8637 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8640 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8644 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8645 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8650 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8651 * loaded or when a record is removed. (defaults to false).
8653 pruneModifiedRecords : false,
8659 * Add Records to the Store and fires the add event.
8660 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8662 add : function(records){
8663 records = [].concat(records);
8664 for(var i = 0, len = records.length; i < len; i++){
8665 records[i].join(this);
8667 var index = this.data.length;
8668 this.data.addAll(records);
8669 this.fireEvent("add", this, records, index);
8673 * Remove a Record from the Store and fires the remove event.
8674 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8676 remove : function(record){
8677 var index = this.data.indexOf(record);
8678 this.data.removeAt(index);
8679 if(this.pruneModifiedRecords){
8680 this.modified.remove(record);
8682 this.fireEvent("remove", this, record, index);
8686 * Remove all Records from the Store and fires the clear event.
8688 removeAll : function(){
8690 if(this.pruneModifiedRecords){
8693 this.fireEvent("clear", this);
8697 * Inserts Records to the Store at the given index and fires the add event.
8698 * @param {Number} index The start index at which to insert the passed Records.
8699 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8701 insert : function(index, records){
8702 records = [].concat(records);
8703 for(var i = 0, len = records.length; i < len; i++){
8704 this.data.insert(index, records[i]);
8705 records[i].join(this);
8707 this.fireEvent("add", this, records, index);
8711 * Get the index within the cache of the passed Record.
8712 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8713 * @return {Number} The index of the passed Record. Returns -1 if not found.
8715 indexOf : function(record){
8716 return this.data.indexOf(record);
8720 * Get the index within the cache of the Record with the passed id.
8721 * @param {String} id The id of the Record to find.
8722 * @return {Number} The index of the Record. Returns -1 if not found.
8724 indexOfId : function(id){
8725 return this.data.indexOfKey(id);
8729 * Get the Record with the specified id.
8730 * @param {String} id The id of the Record to find.
8731 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8733 getById : function(id){
8734 return this.data.key(id);
8738 * Get the Record at the specified index.
8739 * @param {Number} index The index of the Record to find.
8740 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8742 getAt : function(index){
8743 return this.data.itemAt(index);
8747 * Returns a range of Records between specified indices.
8748 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8749 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8750 * @return {Roo.data.Record[]} An array of Records
8752 getRange : function(start, end){
8753 return this.data.getRange(start, end);
8757 storeOptions : function(o){
8758 o = Roo.apply({}, o);
8761 this.lastOptions = o;
8765 * Loads the Record cache from the configured Proxy using the configured Reader.
8767 * If using remote paging, then the first load call must specify the <em>start</em>
8768 * and <em>limit</em> properties in the options.params property to establish the initial
8769 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8771 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8772 * and this call will return before the new data has been loaded. Perform any post-processing
8773 * in a callback function, or in a "load" event handler.</strong>
8775 * @param {Object} options An object containing properties which control loading options:<ul>
8776 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8777 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8778 * passed the following arguments:<ul>
8779 * <li>r : Roo.data.Record[]</li>
8780 * <li>options: Options object from the load call</li>
8781 * <li>success: Boolean success indicator</li></ul></li>
8782 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8783 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8786 load : function(options){
8787 options = options || {};
8788 if(this.fireEvent("beforeload", this, options) !== false){
8789 this.storeOptions(options);
8790 var p = Roo.apply(options.params || {}, this.baseParams);
8791 // if meta was not loaded from remote source.. try requesting it.
8792 if (!this.reader.metaFromRemote) {
8795 if(this.sortInfo && this.remoteSort){
8796 var pn = this.paramNames;
8797 p[pn["sort"]] = this.sortInfo.field;
8798 p[pn["dir"]] = this.sortInfo.direction;
8800 if (this.multiSort) {
8801 var pn = this.paramNames;
8802 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8805 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8810 * Reloads the Record cache from the configured Proxy using the configured Reader and
8811 * the options from the last load operation performed.
8812 * @param {Object} options (optional) An object containing properties which may override the options
8813 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8814 * the most recently used options are reused).
8816 reload : function(options){
8817 this.load(Roo.applyIf(options||{}, this.lastOptions));
8821 // Called as a callback by the Reader during a load operation.
8822 loadRecords : function(o, options, success){
8823 if(!o || success === false){
8824 if(success !== false){
8825 this.fireEvent("load", this, [], options, o);
8827 if(options.callback){
8828 options.callback.call(options.scope || this, [], options, false);
8832 // if data returned failure - throw an exception.
8833 if (o.success === false) {
8834 // show a message if no listener is registered.
8835 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8836 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8838 // loadmask wil be hooked into this..
8839 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8842 var r = o.records, t = o.totalRecords || r.length;
8844 this.fireEvent("beforeloadadd", this, r, options, o);
8846 if(!options || options.add !== true){
8847 if(this.pruneModifiedRecords){
8850 for(var i = 0, len = r.length; i < len; i++){
8854 this.data = this.snapshot;
8855 delete this.snapshot;
8858 this.data.addAll(r);
8859 this.totalLength = t;
8861 this.fireEvent("datachanged", this);
8863 this.totalLength = Math.max(t, this.data.length+r.length);
8866 this.fireEvent("load", this, r, options, o);
8867 if(options.callback){
8868 options.callback.call(options.scope || this, r, options, true);
8874 * Loads data from a passed data block. A Reader which understands the format of the data
8875 * must have been configured in the constructor.
8876 * @param {Object} data The data block from which to read the Records. The format of the data expected
8877 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8878 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8880 loadData : function(o, append){
8881 var r = this.reader.readRecords(o);
8882 this.loadRecords(r, {add: append}, true);
8886 * Gets the number of cached records.
8888 * <em>If using paging, this may not be the total size of the dataset. If the data object
8889 * used by the Reader contains the dataset size, then the getTotalCount() function returns
8890 * the data set size</em>
8892 getCount : function(){
8893 return this.data.length || 0;
8897 * Gets the total number of records in the dataset as returned by the server.
8899 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8900 * the dataset size</em>
8902 getTotalCount : function(){
8903 return this.totalLength || 0;
8907 * Returns the sort state of the Store as an object with two properties:
8909 field {String} The name of the field by which the Records are sorted
8910 direction {String} The sort order, "ASC" or "DESC"
8913 getSortState : function(){
8914 return this.sortInfo;
8918 applySort : function(){
8919 if(this.sortInfo && !this.remoteSort){
8920 var s = this.sortInfo, f = s.field;
8921 var st = this.fields.get(f).sortType;
8922 var fn = function(r1, r2){
8923 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8924 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8926 this.data.sort(s.direction, fn);
8927 if(this.snapshot && this.snapshot != this.data){
8928 this.snapshot.sort(s.direction, fn);
8934 * Sets the default sort column and order to be used by the next load operation.
8935 * @param {String} fieldName The name of the field to sort by.
8936 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8938 setDefaultSort : function(field, dir){
8939 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
8944 * If remote sorting is used, the sort is performed on the server, and the cache is
8945 * reloaded. If local sorting is used, the cache is sorted internally.
8946 * @param {String} fieldName The name of the field to sort by.
8947 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8949 sort : function(fieldName, dir){
8950 var f = this.fields.get(fieldName);
8952 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
8954 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
8955 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
8960 this.sortToggle[f.name] = dir;
8961 this.sortInfo = {field: f.name, direction: dir};
8962 if(!this.remoteSort){
8964 this.fireEvent("datachanged", this);
8966 this.load(this.lastOptions);
8971 * Calls the specified function for each of the Records in the cache.
8972 * @param {Function} fn The function to call. The Record is passed as the first parameter.
8973 * Returning <em>false</em> aborts and exits the iteration.
8974 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
8976 each : function(fn, scope){
8977 this.data.each(fn, scope);
8981 * Gets all records modified since the last commit. Modified records are persisted across load operations
8982 * (e.g., during paging).
8983 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
8985 getModifiedRecords : function(){
8986 return this.modified;
8990 createFilterFn : function(property, value, anyMatch){
8991 if(!value.exec){ // not a regex
8992 value = String(value);
8993 if(value.length == 0){
8996 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
8999 return value.test(r.data[property]);
9004 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9005 * @param {String} property A field on your records
9006 * @param {Number} start The record index to start at (defaults to 0)
9007 * @param {Number} end The last record index to include (defaults to length - 1)
9008 * @return {Number} The sum
9010 sum : function(property, start, end){
9011 var rs = this.data.items, v = 0;
9013 end = (end || end === 0) ? end : rs.length-1;
9015 for(var i = start; i <= end; i++){
9016 v += (rs[i].data[property] || 0);
9022 * Filter the records by a specified property.
9023 * @param {String} field A field on your records
9024 * @param {String/RegExp} value Either a string that the field
9025 * should start with or a RegExp to test against the field
9026 * @param {Boolean} anyMatch True to match any part not just the beginning
9028 filter : function(property, value, anyMatch){
9029 var fn = this.createFilterFn(property, value, anyMatch);
9030 return fn ? this.filterBy(fn) : this.clearFilter();
9034 * Filter by a function. The specified function will be called with each
9035 * record in this data source. If the function returns true the record is included,
9036 * otherwise it is filtered.
9037 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9038 * @param {Object} scope (optional) The scope of the function (defaults to this)
9040 filterBy : function(fn, scope){
9041 this.snapshot = this.snapshot || this.data;
9042 this.data = this.queryBy(fn, scope||this);
9043 this.fireEvent("datachanged", this);
9047 * Query the records by a specified property.
9048 * @param {String} field A field on your records
9049 * @param {String/RegExp} value Either a string that the field
9050 * should start with or a RegExp to test against the field
9051 * @param {Boolean} anyMatch True to match any part not just the beginning
9052 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9054 query : function(property, value, anyMatch){
9055 var fn = this.createFilterFn(property, value, anyMatch);
9056 return fn ? this.queryBy(fn) : this.data.clone();
9060 * Query by a function. The specified function will be called with each
9061 * record in this data source. If the function returns true the record is included
9063 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9064 * @param {Object} scope (optional) The scope of the function (defaults to this)
9065 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9067 queryBy : function(fn, scope){
9068 var data = this.snapshot || this.data;
9069 return data.filterBy(fn, scope||this);
9073 * Collects unique values for a particular dataIndex from this store.
9074 * @param {String} dataIndex The property to collect
9075 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9076 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9077 * @return {Array} An array of the unique values
9079 collect : function(dataIndex, allowNull, bypassFilter){
9080 var d = (bypassFilter === true && this.snapshot) ?
9081 this.snapshot.items : this.data.items;
9082 var v, sv, r = [], l = {};
9083 for(var i = 0, len = d.length; i < len; i++){
9084 v = d[i].data[dataIndex];
9086 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9095 * Revert to a view of the Record cache with no filtering applied.
9096 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9098 clearFilter : function(suppressEvent){
9099 if(this.snapshot && this.snapshot != this.data){
9100 this.data = this.snapshot;
9101 delete this.snapshot;
9102 if(suppressEvent !== true){
9103 this.fireEvent("datachanged", this);
9109 afterEdit : function(record){
9110 if(this.modified.indexOf(record) == -1){
9111 this.modified.push(record);
9113 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9117 afterReject : function(record){
9118 this.modified.remove(record);
9119 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9123 afterCommit : function(record){
9124 this.modified.remove(record);
9125 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9129 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9130 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9132 commitChanges : function(){
9133 var m = this.modified.slice(0);
9135 for(var i = 0, len = m.length; i < len; i++){
9141 * Cancel outstanding changes on all changed records.
9143 rejectChanges : function(){
9144 var m = this.modified.slice(0);
9146 for(var i = 0, len = m.length; i < len; i++){
9151 onMetaChange : function(meta, rtype, o){
9152 this.recordType = rtype;
9153 this.fields = rtype.prototype.fields;
9154 delete this.snapshot;
9155 this.sortInfo = meta.sortInfo || this.sortInfo;
9157 this.fireEvent('metachange', this, this.reader.meta);
9160 moveIndex : function(data, type)
9162 var index = this.indexOf(data);
9164 var newIndex = index + type;
9168 this.insert(newIndex, data);
9173 * Ext JS Library 1.1.1
9174 * Copyright(c) 2006-2007, Ext JS, LLC.
9176 * Originally Released Under LGPL - original licence link has changed is not relivant.
9179 * <script type="text/javascript">
9183 * @class Roo.data.SimpleStore
9184 * @extends Roo.data.Store
9185 * Small helper class to make creating Stores from Array data easier.
9186 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9187 * @cfg {Array} fields An array of field definition objects, or field name strings.
9188 * @cfg {Array} data The multi-dimensional array of data
9190 * @param {Object} config
9192 Roo.data.SimpleStore = function(config){
9193 Roo.data.SimpleStore.superclass.constructor.call(this, {
9195 reader: new Roo.data.ArrayReader({
9198 Roo.data.Record.create(config.fields)
9200 proxy : new Roo.data.MemoryProxy(config.data)
9204 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9206 * Ext JS Library 1.1.1
9207 * Copyright(c) 2006-2007, Ext JS, LLC.
9209 * Originally Released Under LGPL - original licence link has changed is not relivant.
9212 * <script type="text/javascript">
9217 * @extends Roo.data.Store
9218 * @class Roo.data.JsonStore
9219 * Small helper class to make creating Stores for JSON data easier. <br/>
9221 var store = new Roo.data.JsonStore({
9222 url: 'get-images.php',
9224 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9227 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9228 * JsonReader and HttpProxy (unless inline data is provided).</b>
9229 * @cfg {Array} fields An array of field definition objects, or field name strings.
9231 * @param {Object} config
9233 Roo.data.JsonStore = function(c){
9234 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9235 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9236 reader: new Roo.data.JsonReader(c, c.fields)
9239 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9241 * Ext JS Library 1.1.1
9242 * Copyright(c) 2006-2007, Ext JS, LLC.
9244 * Originally Released Under LGPL - original licence link has changed is not relivant.
9247 * <script type="text/javascript">
9251 Roo.data.Field = function(config){
9252 if(typeof config == "string"){
9253 config = {name: config};
9255 Roo.apply(this, config);
9261 var st = Roo.data.SortTypes;
9262 // named sortTypes are supported, here we look them up
9263 if(typeof this.sortType == "string"){
9264 this.sortType = st[this.sortType];
9267 // set default sortType for strings and dates
9271 this.sortType = st.asUCString;
9274 this.sortType = st.asDate;
9277 this.sortType = st.none;
9282 var stripRe = /[\$,%]/g;
9284 // prebuilt conversion function for this field, instead of
9285 // switching every time we're reading a value
9287 var cv, dateFormat = this.dateFormat;
9292 cv = function(v){ return v; };
9295 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9299 return v !== undefined && v !== null && v !== '' ?
9300 parseInt(String(v).replace(stripRe, ""), 10) : '';
9305 return v !== undefined && v !== null && v !== '' ?
9306 parseFloat(String(v).replace(stripRe, ""), 10) : '';
9311 cv = function(v){ return v === true || v === "true" || v == 1; };
9318 if(v instanceof Date){
9322 if(dateFormat == "timestamp"){
9323 return new Date(v*1000);
9325 return Date.parseDate(v, dateFormat);
9327 var parsed = Date.parse(v);
9328 return parsed ? new Date(parsed) : null;
9337 Roo.data.Field.prototype = {
9345 * Ext JS Library 1.1.1
9346 * Copyright(c) 2006-2007, Ext JS, LLC.
9348 * Originally Released Under LGPL - original licence link has changed is not relivant.
9351 * <script type="text/javascript">
9354 // Base class for reading structured data from a data source. This class is intended to be
9355 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9358 * @class Roo.data.DataReader
9359 * Base class for reading structured data from a data source. This class is intended to be
9360 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9363 Roo.data.DataReader = function(meta, recordType){
9367 this.recordType = recordType instanceof Array ?
9368 Roo.data.Record.create(recordType) : recordType;
9371 Roo.data.DataReader.prototype = {
9373 * Create an empty record
9374 * @param {Object} data (optional) - overlay some values
9375 * @return {Roo.data.Record} record created.
9377 newRow : function(d) {
9379 this.recordType.prototype.fields.each(function(c) {
9381 case 'int' : da[c.name] = 0; break;
9382 case 'date' : da[c.name] = new Date(); break;
9383 case 'float' : da[c.name] = 0.0; break;
9384 case 'boolean' : da[c.name] = false; break;
9385 default : da[c.name] = ""; break;
9389 return new this.recordType(Roo.apply(da, d));
9394 * Ext JS Library 1.1.1
9395 * Copyright(c) 2006-2007, Ext JS, LLC.
9397 * Originally Released Under LGPL - original licence link has changed is not relivant.
9400 * <script type="text/javascript">
9404 * @class Roo.data.DataProxy
9405 * @extends Roo.data.Observable
9406 * This class is an abstract base class for implementations which provide retrieval of
9407 * unformatted data objects.<br>
9409 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9410 * (of the appropriate type which knows how to parse the data object) to provide a block of
9411 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9413 * Custom implementations must implement the load method as described in
9414 * {@link Roo.data.HttpProxy#load}.
9416 Roo.data.DataProxy = function(){
9420 * Fires before a network request is made to retrieve a data object.
9421 * @param {Object} This DataProxy object.
9422 * @param {Object} params The params parameter to the load function.
9427 * Fires before the load method's callback is called.
9428 * @param {Object} This DataProxy object.
9429 * @param {Object} o The data object.
9430 * @param {Object} arg The callback argument object passed to the load function.
9434 * @event loadexception
9435 * Fires if an Exception occurs during data retrieval.
9436 * @param {Object} This DataProxy object.
9437 * @param {Object} o The data object.
9438 * @param {Object} arg The callback argument object passed to the load function.
9439 * @param {Object} e The Exception.
9441 loadexception : true
9443 Roo.data.DataProxy.superclass.constructor.call(this);
9446 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9449 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9453 * Ext JS Library 1.1.1
9454 * Copyright(c) 2006-2007, Ext JS, LLC.
9456 * Originally Released Under LGPL - original licence link has changed is not relivant.
9459 * <script type="text/javascript">
9462 * @class Roo.data.MemoryProxy
9463 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9464 * to the Reader when its load method is called.
9466 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9468 Roo.data.MemoryProxy = function(data){
9472 Roo.data.MemoryProxy.superclass.constructor.call(this);
9476 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9478 * Load data from the requested source (in this case an in-memory
9479 * data object passed to the constructor), read the data object into
9480 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9481 * process that block using the passed callback.
9482 * @param {Object} params This parameter is not used by the MemoryProxy class.
9483 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9484 * object into a block of Roo.data.Records.
9485 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9486 * The function must be passed <ul>
9487 * <li>The Record block object</li>
9488 * <li>The "arg" argument from the load function</li>
9489 * <li>A boolean success indicator</li>
9491 * @param {Object} scope The scope in which to call the callback
9492 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9494 load : function(params, reader, callback, scope, arg){
9495 params = params || {};
9498 result = reader.readRecords(this.data);
9500 this.fireEvent("loadexception", this, arg, null, e);
9501 callback.call(scope, null, arg, false);
9504 callback.call(scope, result, arg, true);
9508 update : function(params, records){
9513 * Ext JS Library 1.1.1
9514 * Copyright(c) 2006-2007, Ext JS, LLC.
9516 * Originally Released Under LGPL - original licence link has changed is not relivant.
9519 * <script type="text/javascript">
9522 * @class Roo.data.HttpProxy
9523 * @extends Roo.data.DataProxy
9524 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9525 * configured to reference a certain URL.<br><br>
9527 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9528 * from which the running page was served.<br><br>
9530 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9532 * Be aware that to enable the browser to parse an XML document, the server must set
9533 * the Content-Type header in the HTTP response to "text/xml".
9535 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9536 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9537 * will be used to make the request.
9539 Roo.data.HttpProxy = function(conn){
9540 Roo.data.HttpProxy.superclass.constructor.call(this);
9541 // is conn a conn config or a real conn?
9543 this.useAjax = !conn || !conn.events;
9547 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9548 // thse are take from connection...
9551 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9554 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9555 * extra parameters to each request made by this object. (defaults to undefined)
9558 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9559 * to each request made by this object. (defaults to undefined)
9562 * @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)
9565 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9568 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9574 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9578 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9579 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9580 * a finer-grained basis than the DataProxy events.
9582 getConnection : function(){
9583 return this.useAjax ? Roo.Ajax : this.conn;
9587 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9588 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9589 * process that block using the passed callback.
9590 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9591 * for the request to the remote server.
9592 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9593 * object into a block of Roo.data.Records.
9594 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9595 * The function must be passed <ul>
9596 * <li>The Record block object</li>
9597 * <li>The "arg" argument from the load function</li>
9598 * <li>A boolean success indicator</li>
9600 * @param {Object} scope The scope in which to call the callback
9601 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9603 load : function(params, reader, callback, scope, arg){
9604 if(this.fireEvent("beforeload", this, params) !== false){
9606 params : params || {},
9608 callback : callback,
9613 callback : this.loadResponse,
9617 Roo.applyIf(o, this.conn);
9618 if(this.activeRequest){
9619 Roo.Ajax.abort(this.activeRequest);
9621 this.activeRequest = Roo.Ajax.request(o);
9623 this.conn.request(o);
9626 callback.call(scope||this, null, arg, false);
9631 loadResponse : function(o, success, response){
9632 delete this.activeRequest;
9634 this.fireEvent("loadexception", this, o, response);
9635 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9640 result = o.reader.read(response);
9642 this.fireEvent("loadexception", this, o, response, e);
9643 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9647 this.fireEvent("load", this, o, o.request.arg);
9648 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9652 update : function(dataSet){
9657 updateResponse : function(dataSet){
9662 * Ext JS Library 1.1.1
9663 * Copyright(c) 2006-2007, Ext JS, LLC.
9665 * Originally Released Under LGPL - original licence link has changed is not relivant.
9668 * <script type="text/javascript">
9672 * @class Roo.data.ScriptTagProxy
9673 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9674 * other than the originating domain of the running page.<br><br>
9676 * <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
9677 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9679 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9680 * source code that is used as the source inside a <script> tag.<br><br>
9682 * In order for the browser to process the returned data, the server must wrap the data object
9683 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9684 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9685 * depending on whether the callback name was passed:
9688 boolean scriptTag = false;
9689 String cb = request.getParameter("callback");
9692 response.setContentType("text/javascript");
9694 response.setContentType("application/x-json");
9696 Writer out = response.getWriter();
9698 out.write(cb + "(");
9700 out.print(dataBlock.toJsonString());
9707 * @param {Object} config A configuration object.
9709 Roo.data.ScriptTagProxy = function(config){
9710 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9711 Roo.apply(this, config);
9712 this.head = document.getElementsByTagName("head")[0];
9715 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9717 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9719 * @cfg {String} url The URL from which to request the data object.
9722 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9726 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9727 * the server the name of the callback function set up by the load call to process the returned data object.
9728 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9729 * javascript output which calls this named function passing the data object as its only parameter.
9731 callbackParam : "callback",
9733 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9734 * name to the request.
9739 * Load data from the configured URL, read the data object into
9740 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9741 * process that block using the passed callback.
9742 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9743 * for the request to the remote server.
9744 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9745 * object into a block of Roo.data.Records.
9746 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9747 * The function must be passed <ul>
9748 * <li>The Record block object</li>
9749 * <li>The "arg" argument from the load function</li>
9750 * <li>A boolean success indicator</li>
9752 * @param {Object} scope The scope in which to call the callback
9753 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9755 load : function(params, reader, callback, scope, arg){
9756 if(this.fireEvent("beforeload", this, params) !== false){
9758 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9761 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9763 url += "&_dc=" + (new Date().getTime());
9765 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9768 cb : "stcCallback"+transId,
9769 scriptId : "stcScript"+transId,
9773 callback : callback,
9779 window[trans.cb] = function(o){
9780 conn.handleResponse(o, trans);
9783 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9785 if(this.autoAbort !== false){
9789 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9791 var script = document.createElement("script");
9792 script.setAttribute("src", url);
9793 script.setAttribute("type", "text/javascript");
9794 script.setAttribute("id", trans.scriptId);
9795 this.head.appendChild(script);
9799 callback.call(scope||this, null, arg, false);
9804 isLoading : function(){
9805 return this.trans ? true : false;
9809 * Abort the current server request.
9812 if(this.isLoading()){
9813 this.destroyTrans(this.trans);
9818 destroyTrans : function(trans, isLoaded){
9819 this.head.removeChild(document.getElementById(trans.scriptId));
9820 clearTimeout(trans.timeoutId);
9822 window[trans.cb] = undefined;
9824 delete window[trans.cb];
9827 // if hasn't been loaded, wait for load to remove it to prevent script error
9828 window[trans.cb] = function(){
9829 window[trans.cb] = undefined;
9831 delete window[trans.cb];
9838 handleResponse : function(o, trans){
9840 this.destroyTrans(trans, true);
9843 result = trans.reader.readRecords(o);
9845 this.fireEvent("loadexception", this, o, trans.arg, e);
9846 trans.callback.call(trans.scope||window, null, trans.arg, false);
9849 this.fireEvent("load", this, o, trans.arg);
9850 trans.callback.call(trans.scope||window, result, trans.arg, true);
9854 handleFailure : function(trans){
9856 this.destroyTrans(trans, false);
9857 this.fireEvent("loadexception", this, null, trans.arg);
9858 trans.callback.call(trans.scope||window, null, trans.arg, false);
9862 * Ext JS Library 1.1.1
9863 * Copyright(c) 2006-2007, Ext JS, LLC.
9865 * Originally Released Under LGPL - original licence link has changed is not relivant.
9868 * <script type="text/javascript">
9872 * @class Roo.data.JsonReader
9873 * @extends Roo.data.DataReader
9874 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9875 * based on mappings in a provided Roo.data.Record constructor.
9877 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9878 * in the reply previously.
9883 var RecordDef = Roo.data.Record.create([
9884 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
9885 {name: 'occupation'} // This field will use "occupation" as the mapping.
9887 var myReader = new Roo.data.JsonReader({
9888 totalProperty: "results", // The property which contains the total dataset size (optional)
9889 root: "rows", // The property which contains an Array of row objects
9890 id: "id" // The property within each row object that provides an ID for the record (optional)
9894 * This would consume a JSON file like this:
9896 { 'results': 2, 'rows': [
9897 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9898 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9901 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9902 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9903 * paged from the remote server.
9904 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9905 * @cfg {String} root name of the property which contains the Array of row objects.
9906 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9908 * Create a new JsonReader
9909 * @param {Object} meta Metadata configuration options
9910 * @param {Object} recordType Either an Array of field definition objects,
9911 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9913 Roo.data.JsonReader = function(meta, recordType){
9916 // set some defaults:
9918 totalProperty: 'total',
9919 successProperty : 'success',
9924 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9926 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9929 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
9930 * Used by Store query builder to append _requestMeta to params.
9933 metaFromRemote : false,
9935 * This method is only used by a DataProxy which has retrieved data from a remote server.
9936 * @param {Object} response The XHR object which contains the JSON data in its responseText.
9937 * @return {Object} data A data block which is used by an Roo.data.Store object as
9938 * a cache of Roo.data.Records.
9940 read : function(response){
9941 var json = response.responseText;
9943 var o = /* eval:var:o */ eval("("+json+")");
9945 throw {message: "JsonReader.read: Json object not found"};
9951 this.metaFromRemote = true;
9952 this.meta = o.metaData;
9953 this.recordType = Roo.data.Record.create(o.metaData.fields);
9954 this.onMetaChange(this.meta, this.recordType, o);
9956 return this.readRecords(o);
9959 // private function a store will implement
9960 onMetaChange : function(meta, recordType, o){
9967 simpleAccess: function(obj, subsc) {
9974 getJsonAccessor: function(){
9976 return function(expr) {
9978 return(re.test(expr))
9979 ? new Function("obj", "return obj." + expr)
9989 * Create a data block containing Roo.data.Records from an XML document.
9990 * @param {Object} o An object which contains an Array of row objects in the property specified
9991 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
9992 * which contains the total size of the dataset.
9993 * @return {Object} data A data block which is used by an Roo.data.Store object as
9994 * a cache of Roo.data.Records.
9996 readRecords : function(o){
9998 * After any data loads, the raw JSON data is available for further custom processing.
10002 var s = this.meta, Record = this.recordType,
10003 f = Record.prototype.fields, fi = f.items, fl = f.length;
10005 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10007 if(s.totalProperty) {
10008 this.getTotal = this.getJsonAccessor(s.totalProperty);
10010 if(s.successProperty) {
10011 this.getSuccess = this.getJsonAccessor(s.successProperty);
10013 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10015 var g = this.getJsonAccessor(s.id);
10016 this.getId = function(rec) {
10018 return (r === undefined || r === "") ? null : r;
10021 this.getId = function(){return null;};
10024 for(var jj = 0; jj < fl; jj++){
10026 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10027 this.ef[jj] = this.getJsonAccessor(map);
10031 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10032 if(s.totalProperty){
10033 var vt = parseInt(this.getTotal(o), 10);
10038 if(s.successProperty){
10039 var vs = this.getSuccess(o);
10040 if(vs === false || vs === 'false'){
10045 for(var i = 0; i < c; i++){
10048 var id = this.getId(n);
10049 for(var j = 0; j < fl; j++){
10051 var v = this.ef[j](n);
10053 Roo.log('missing convert for ' + f.name);
10057 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10059 var record = new Record(values, id);
10061 records[i] = record;
10067 totalRecords : totalRecords
10072 * Ext JS Library 1.1.1
10073 * Copyright(c) 2006-2007, Ext JS, LLC.
10075 * Originally Released Under LGPL - original licence link has changed is not relivant.
10078 * <script type="text/javascript">
10082 * @class Roo.data.ArrayReader
10083 * @extends Roo.data.DataReader
10084 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10085 * Each element of that Array represents a row of data fields. The
10086 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10087 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10091 var RecordDef = Roo.data.Record.create([
10092 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10093 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10095 var myReader = new Roo.data.ArrayReader({
10096 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10100 * This would consume an Array like this:
10102 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10104 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10106 * Create a new JsonReader
10107 * @param {Object} meta Metadata configuration options.
10108 * @param {Object} recordType Either an Array of field definition objects
10109 * as specified to {@link Roo.data.Record#create},
10110 * or an {@link Roo.data.Record} object
10111 * created using {@link Roo.data.Record#create}.
10113 Roo.data.ArrayReader = function(meta, recordType){
10114 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10117 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10119 * Create a data block containing Roo.data.Records from an XML document.
10120 * @param {Object} o An Array of row objects which represents the dataset.
10121 * @return {Object} data A data block which is used by an Roo.data.Store object as
10122 * a cache of Roo.data.Records.
10124 readRecords : function(o){
10125 var sid = this.meta ? this.meta.id : null;
10126 var recordType = this.recordType, fields = recordType.prototype.fields;
10129 for(var i = 0; i < root.length; i++){
10132 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10133 for(var j = 0, jlen = fields.length; j < jlen; j++){
10134 var f = fields.items[j];
10135 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10136 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10138 values[f.name] = v;
10140 var record = new recordType(values, id);
10142 records[records.length] = record;
10146 totalRecords : records.length
10155 * @class Roo.bootstrap.ComboBox
10156 * @extends Roo.bootstrap.TriggerField
10157 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10158 * @cfg {Boolean} append (true|false) default false
10159 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10160 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10161 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10162 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10163 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10165 * Create a new ComboBox.
10166 * @param {Object} config Configuration options
10168 Roo.bootstrap.ComboBox = function(config){
10169 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10173 * Fires when the dropdown list is expanded
10174 * @param {Roo.bootstrap.ComboBox} combo This combo box
10179 * Fires when the dropdown list is collapsed
10180 * @param {Roo.bootstrap.ComboBox} combo This combo box
10184 * @event beforeselect
10185 * Fires before a list item is selected. Return false to cancel the selection.
10186 * @param {Roo.bootstrap.ComboBox} combo This combo box
10187 * @param {Roo.data.Record} record The data record returned from the underlying store
10188 * @param {Number} index The index of the selected item in the dropdown list
10190 'beforeselect' : true,
10193 * Fires when a list item is selected
10194 * @param {Roo.bootstrap.ComboBox} combo This combo box
10195 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10196 * @param {Number} index The index of the selected item in the dropdown list
10200 * @event beforequery
10201 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10202 * The event object passed has these properties:
10203 * @param {Roo.bootstrap.ComboBox} combo This combo box
10204 * @param {String} query The query
10205 * @param {Boolean} forceAll true to force "all" query
10206 * @param {Boolean} cancel true to cancel the query
10207 * @param {Object} e The query event object
10209 'beforequery': true,
10212 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10213 * @param {Roo.bootstrap.ComboBox} combo This combo box
10218 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10219 * @param {Roo.bootstrap.ComboBox} combo This combo box
10220 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10225 * Fires when the remove value from the combobox array
10226 * @param {Roo.bootstrap.ComboBox} combo This combo box
10233 this.tickItems = [];
10235 this.selectedIndex = -1;
10236 if(this.mode == 'local'){
10237 if(config.queryDelay === undefined){
10238 this.queryDelay = 10;
10240 if(config.minChars === undefined){
10246 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10249 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10250 * rendering into an Roo.Editor, defaults to false)
10253 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10254 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10257 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10260 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10261 * the dropdown list (defaults to undefined, with no header element)
10265 * @cfg {String/Roo.Template} tpl The template to use to render the output
10269 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10271 listWidth: undefined,
10273 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10274 * mode = 'remote' or 'text' if mode = 'local')
10276 displayField: undefined,
10278 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10279 * mode = 'remote' or 'value' if mode = 'local').
10280 * Note: use of a valueField requires the user make a selection
10281 * in order for a value to be mapped.
10283 valueField: undefined,
10287 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10288 * field's data value (defaults to the underlying DOM element's name)
10290 hiddenName: undefined,
10292 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10296 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10298 selectedClass: 'active',
10301 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10305 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10306 * anchor positions (defaults to 'tl-bl')
10308 listAlign: 'tl-bl?',
10310 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10314 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
10315 * query specified by the allQuery config option (defaults to 'query')
10317 triggerAction: 'query',
10319 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10320 * (defaults to 4, does not apply if editable = false)
10324 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10325 * delay (typeAheadDelay) if it matches a known value (defaults to false)
10329 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10330 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10334 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10335 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
10339 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
10340 * when editable = true (defaults to false)
10342 selectOnFocus:false,
10344 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10346 queryParam: 'query',
10348 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
10349 * when mode = 'remote' (defaults to 'Loading...')
10351 loadingText: 'Loading...',
10353 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10357 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10361 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10362 * traditional select (defaults to true)
10366 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10370 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10374 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10375 * listWidth has a higher value)
10379 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10380 * allow the user to set arbitrary text into the field (defaults to false)
10382 forceSelection:false,
10384 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10385 * if typeAhead = true (defaults to 250)
10387 typeAheadDelay : 250,
10389 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10390 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10392 valueNotFoundText : undefined,
10394 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10396 blockFocus : false,
10399 * @cfg {Boolean} disableClear Disable showing of clear button.
10401 disableClear : false,
10403 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
10405 alwaysQuery : false,
10408 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
10422 btnPosition : 'right',
10423 triggerList : true,
10424 showToggleBtn : true,
10425 // element that contains real text value.. (when hidden is used..)
10427 getAutoCreate : function()
10434 if(!this.tickable){
10435 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10440 * ComboBox with tickable selections
10443 var align = this.labelAlign || this.parentLabelAlign();
10446 cls : 'form-group roo-combobox-tickable' //input-group
10452 cls : 'tickable-buttons',
10457 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10464 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10471 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10478 Roo.each(buttons.cn, function(c){
10480 c.cls += ' btn-' + _this.size;
10483 if (_this.disabled) {
10494 cls: 'form-hidden-field'
10498 cls: 'select2-choices',
10502 cls: 'select2-search-field',
10514 cls: 'select2-container input-group select2-container-multi',
10519 // cls: 'typeahead typeahead-long dropdown-menu',
10520 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
10525 if (align ==='left' && this.fieldLabel.length) {
10527 Roo.log("left and has label");
10533 cls : 'control-label col-sm-' + this.labelWidth,
10534 html : this.fieldLabel
10538 cls : "col-sm-" + (12 - this.labelWidth),
10545 } else if ( this.fieldLabel.length) {
10551 //cls : 'input-group-addon',
10552 html : this.fieldLabel
10562 Roo.log(" no label && no align");
10569 ['xs','sm','md','lg'].map(function(size){
10570 if (settings[size]) {
10571 cfg.cls += ' col-' + size + '-' + settings[size];
10580 initEvents: function()
10584 throw "can not find store for combo";
10586 this.store = Roo.factory(this.store, Roo.data);
10589 this.initTickableEvents();
10593 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10595 if(this.hiddenName){
10597 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10599 this.hiddenField.dom.value =
10600 this.hiddenValue !== undefined ? this.hiddenValue :
10601 this.value !== undefined ? this.value : '';
10603 // prevent input submission
10604 this.el.dom.removeAttribute('name');
10605 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10610 // this.el.dom.setAttribute('autocomplete', 'off');
10613 var cls = 'x-combo-list';
10615 //this.list = new Roo.Layer({
10616 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10622 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10623 _this.list.setWidth(lw);
10626 this.list.on('mouseover', this.onViewOver, this);
10627 this.list.on('mousemove', this.onViewMove, this);
10629 this.list.on('scroll', this.onViewScroll, this);
10632 this.list.swallowEvent('mousewheel');
10633 this.assetHeight = 0;
10636 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10637 this.assetHeight += this.header.getHeight();
10640 this.innerList = this.list.createChild({cls:cls+'-inner'});
10641 this.innerList.on('mouseover', this.onViewOver, this);
10642 this.innerList.on('mousemove', this.onViewMove, this);
10643 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10645 if(this.allowBlank && !this.pageSize && !this.disableClear){
10646 this.footer = this.list.createChild({cls:cls+'-ft'});
10647 this.pageTb = new Roo.Toolbar(this.footer);
10651 this.footer = this.list.createChild({cls:cls+'-ft'});
10652 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10653 {pageSize: this.pageSize});
10657 if (this.pageTb && this.allowBlank && !this.disableClear) {
10659 this.pageTb.add(new Roo.Toolbar.Fill(), {
10660 cls: 'x-btn-icon x-btn-clear',
10662 handler: function()
10665 _this.clearValue();
10666 _this.onSelect(false, -1);
10671 this.assetHeight += this.footer.getHeight();
10676 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10679 this.view = new Roo.View(this.list, this.tpl, {
10680 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10682 //this.view.wrapEl.setDisplayed(false);
10683 this.view.on('click', this.onViewClick, this);
10687 this.store.on('beforeload', this.onBeforeLoad, this);
10688 this.store.on('load', this.onLoad, this);
10689 this.store.on('loadexception', this.onLoadException, this);
10691 if(this.resizable){
10692 this.resizer = new Roo.Resizable(this.list, {
10693 pinned:true, handles:'se'
10695 this.resizer.on('resize', function(r, w, h){
10696 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10697 this.listWidth = w;
10698 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10699 this.restrictHeight();
10701 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10704 if(!this.editable){
10705 this.editable = true;
10706 this.setEditable(false);
10711 if (typeof(this.events.add.listeners) != 'undefined') {
10713 this.addicon = this.wrap.createChild(
10714 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10716 this.addicon.on('click', function(e) {
10717 this.fireEvent('add', this);
10720 if (typeof(this.events.edit.listeners) != 'undefined') {
10722 this.editicon = this.wrap.createChild(
10723 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10724 if (this.addicon) {
10725 this.editicon.setStyle('margin-left', '40px');
10727 this.editicon.on('click', function(e) {
10729 // we fire even if inothing is selected..
10730 this.fireEvent('edit', this, this.lastData );
10736 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10737 "up" : function(e){
10738 this.inKeyMode = true;
10742 "down" : function(e){
10743 if(!this.isExpanded()){
10744 this.onTriggerClick();
10746 this.inKeyMode = true;
10751 "enter" : function(e){
10752 // this.onViewClick();
10756 if(this.fireEvent("specialkey", this, e)){
10757 this.onViewClick(false);
10763 "esc" : function(e){
10767 "tab" : function(e){
10770 if(this.fireEvent("specialkey", this, e)){
10771 this.onViewClick(false);
10779 doRelay : function(foo, bar, hname){
10780 if(hname == 'down' || this.scope.isExpanded()){
10781 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10790 this.queryDelay = Math.max(this.queryDelay || 10,
10791 this.mode == 'local' ? 10 : 250);
10794 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10796 if(this.typeAhead){
10797 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10799 if(this.editable !== false){
10800 this.inputEl().on("keyup", this.onKeyUp, this);
10802 if(this.forceSelection){
10803 this.inputEl().on('blur', this.doForce, this);
10807 this.choices = this.el.select('ul.select2-choices', true).first();
10808 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10812 initTickableEvents: function()
10816 if(this.hiddenName){
10818 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10820 this.hiddenField.dom.value =
10821 this.hiddenValue !== undefined ? this.hiddenValue :
10822 this.value !== undefined ? this.value : '';
10824 // prevent input submission
10825 this.el.dom.removeAttribute('name');
10826 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10831 // this.list = this.el.select('ul.dropdown-menu',true).first();
10833 this.choices = this.el.select('ul.select2-choices', true).first();
10834 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10835 if(this.triggerList){
10836 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
10839 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10840 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
10842 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10843 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10845 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10846 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10848 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10849 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10850 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10853 this.cancelBtn.hide();
10858 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10859 _this.list.setWidth(lw);
10862 this.list.on('mouseover', this.onViewOver, this);
10863 this.list.on('mousemove', this.onViewMove, this);
10865 this.list.on('scroll', this.onViewScroll, this);
10868 this.tpl = '<li class="select2-result"><div class="checkbox"><input id="{roo-id}" type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></li>';
10871 this.view = new Roo.View(this.list, this.tpl, {
10872 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10875 //this.view.wrapEl.setDisplayed(false);
10876 this.view.on('click', this.onViewClick, this);
10880 this.store.on('beforeload', this.onBeforeLoad, this);
10881 this.store.on('load', this.onLoad, this);
10882 this.store.on('loadexception', this.onLoadException, this);
10884 // this.keyNav = new Roo.KeyNav(this.inputEl(), {
10885 // "up" : function(e){
10886 // this.inKeyMode = true;
10887 // this.selectPrev();
10890 // "down" : function(e){
10891 // if(!this.isExpanded()){
10892 // this.onTriggerClick();
10894 // this.inKeyMode = true;
10895 // this.selectNext();
10899 // "enter" : function(e){
10900 //// this.onViewClick();
10902 // this.collapse();
10904 // if(this.fireEvent("specialkey", this, e)){
10905 // this.onViewClick(false);
10911 // "esc" : function(e){
10912 // this.collapse();
10915 // "tab" : function(e){
10916 // this.collapse();
10918 // if(this.fireEvent("specialkey", this, e)){
10919 // this.onViewClick(false);
10927 // doRelay : function(foo, bar, hname){
10928 // if(hname == 'down' || this.scope.isExpanded()){
10929 // return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10934 // forceKeyDown: true
10938 this.queryDelay = Math.max(this.queryDelay || 10,
10939 this.mode == 'local' ? 10 : 250);
10942 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10944 if(this.typeAhead){
10945 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10949 onDestroy : function(){
10951 this.view.setStore(null);
10952 this.view.el.removeAllListeners();
10953 this.view.el.remove();
10954 this.view.purgeListeners();
10957 this.list.dom.innerHTML = '';
10961 this.store.un('beforeload', this.onBeforeLoad, this);
10962 this.store.un('load', this.onLoad, this);
10963 this.store.un('loadexception', this.onLoadException, this);
10965 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
10969 fireKey : function(e){
10970 if(e.isNavKeyPress() && !this.list.isVisible()){
10971 this.fireEvent("specialkey", this, e);
10976 onResize: function(w, h){
10977 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
10979 // if(typeof w != 'number'){
10980 // // we do not handle it!?!?
10983 // var tw = this.trigger.getWidth();
10984 // // tw += this.addicon ? this.addicon.getWidth() : 0;
10985 // // tw += this.editicon ? this.editicon.getWidth() : 0;
10987 // this.inputEl().setWidth( this.adjustWidth('input', x));
10989 // //this.trigger.setStyle('left', x+'px');
10991 // if(this.list && this.listWidth === undefined){
10992 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
10993 // this.list.setWidth(lw);
10994 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11002 * Allow or prevent the user from directly editing the field text. If false is passed,
11003 * the user will only be able to select from the items defined in the dropdown list. This method
11004 * is the runtime equivalent of setting the 'editable' config option at config time.
11005 * @param {Boolean} value True to allow the user to directly edit the field text
11007 setEditable : function(value){
11008 if(value == this.editable){
11011 this.editable = value;
11013 this.inputEl().dom.setAttribute('readOnly', true);
11014 this.inputEl().on('mousedown', this.onTriggerClick, this);
11015 this.inputEl().addClass('x-combo-noedit');
11017 this.inputEl().dom.setAttribute('readOnly', false);
11018 this.inputEl().un('mousedown', this.onTriggerClick, this);
11019 this.inputEl().removeClass('x-combo-noedit');
11025 onBeforeLoad : function(combo,opts){
11026 if(!this.hasFocus){
11030 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11032 // this.restrictHeight();
11033 this.selectedIndex = -1;
11037 onLoad : function(){
11039 this.hasQuery = false;
11041 if(!this.hasFocus){
11045 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11046 this.loading.hide();
11049 if(this.store.getCount() > 0){
11051 // this.restrictHeight();
11052 if(this.lastQuery == this.allQuery){
11053 if(this.editable && !this.tickable){
11054 this.inputEl().dom.select();
11057 if(!this.selectByValue(this.value, true) && this.autoFocus && (typeof(this.store.lastOptions.add) == 'undefined' || this.store.lastOptions.add != true)){
11058 this.select(0, true);
11061 if(this.autoFocus){
11064 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11065 this.taTask.delay(this.typeAheadDelay);
11069 this.onEmptyResults();
11075 onLoadException : function()
11077 this.hasQuery = false;
11079 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11080 this.loading.hide();
11084 Roo.log(this.store.reader.jsonData);
11085 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11087 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11093 onTypeAhead : function(){
11094 if(this.store.getCount() > 0){
11095 var r = this.store.getAt(0);
11096 var newValue = r.data[this.displayField];
11097 var len = newValue.length;
11098 var selStart = this.getRawValue().length;
11100 if(selStart != len){
11101 this.setRawValue(newValue);
11102 this.selectText(selStart, newValue.length);
11108 onSelect : function(record, index){
11110 if(this.fireEvent('beforeselect', this, record, index) !== false){
11112 this.setFromData(index > -1 ? record.data : false);
11115 this.fireEvent('select', this, record, index);
11120 * Returns the currently selected field value or empty string if no value is set.
11121 * @return {String} value The selected value
11123 getValue : function(){
11126 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11129 if(this.valueField){
11130 return typeof this.value != 'undefined' ? this.value : '';
11132 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11137 * Clears any text/value currently set in the field
11139 clearValue : function(){
11140 if(this.hiddenField){
11141 this.hiddenField.dom.value = '';
11144 this.setRawValue('');
11145 this.lastSelectionText = '';
11150 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11151 * will be displayed in the field. If the value does not match the data value of an existing item,
11152 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11153 * Otherwise the field will be blank (although the value will still be set).
11154 * @param {String} value The value to match
11156 setValue : function(v){
11163 if(this.valueField){
11164 var r = this.findRecord(this.valueField, v);
11166 text = r.data[this.displayField];
11167 }else if(this.valueNotFoundText !== undefined){
11168 text = this.valueNotFoundText;
11171 this.lastSelectionText = text;
11172 if(this.hiddenField){
11173 this.hiddenField.dom.value = v;
11175 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11179 * @property {Object} the last set data for the element
11184 * Sets the value of the field based on a object which is related to the record format for the store.
11185 * @param {Object} value the value to set as. or false on reset?
11187 setFromData : function(o){
11190 if(typeof o.display_name !== 'string'){
11191 for(var i=0;i<o.display_name.length;i++){
11192 this.addItem({'id':o.id[i],'display_name':o.display_name[i]});
11200 var dv = ''; // display value
11201 var vv = ''; // value value..
11203 if (this.displayField) {
11204 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11206 // this is an error condition!!!
11207 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11210 if(this.valueField){
11211 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11214 if(this.hiddenField){
11215 this.hiddenField.dom.value = vv;
11217 this.lastSelectionText = dv;
11218 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11222 // no hidden field.. - we store the value in 'value', but still display
11223 // display field!!!!
11224 this.lastSelectionText = dv;
11225 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11231 reset : function(){
11232 // overridden so that last data is reset..
11233 this.setValue(this.originalValue);
11234 this.clearInvalid();
11235 this.lastData = false;
11237 this.view.clearSelections();
11241 findRecord : function(prop, value){
11243 if(this.store.getCount() > 0){
11244 this.store.each(function(r){
11245 if(r.data[prop] == value){
11255 getName: function()
11257 // returns hidden if it's set..
11258 if (!this.rendered) {return ''};
11259 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
11263 onViewMove : function(e, t){
11264 this.inKeyMode = false;
11268 onViewOver : function(e, t){
11269 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11272 var item = this.view.findItemFromChild(t);
11275 var index = this.view.indexOf(item);
11276 this.select(index, false);
11281 onViewClick : function(view, doFocus, el, e)
11283 var index = this.view.getSelectedIndexes()[0];
11285 var r = this.store.getAt(index);
11289 if(e.getTarget().nodeName.toLowerCase() != 'input'){
11296 Roo.each(this.tickItems, function(v,k){
11298 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11299 _this.tickItems.splice(k, 1);
11309 this.tickItems.push(r.data);
11314 this.onSelect(r, index);
11316 if(doFocus !== false && !this.blockFocus){
11317 this.inputEl().focus();
11322 restrictHeight : function(){
11323 //this.innerList.dom.style.height = '';
11324 //var inner = this.innerList.dom;
11325 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11326 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11327 //this.list.beginUpdate();
11328 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11329 this.list.alignTo(this.inputEl(), this.listAlign);
11330 this.list.alignTo(this.inputEl(), this.listAlign);
11331 //this.list.endUpdate();
11335 onEmptyResults : function(){
11340 * Returns true if the dropdown list is expanded, else false.
11342 isExpanded : function(){
11343 return this.list.isVisible();
11347 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11348 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11349 * @param {String} value The data value of the item to select
11350 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11351 * selected item if it is not currently in view (defaults to true)
11352 * @return {Boolean} True if the value matched an item in the list, else false
11354 selectByValue : function(v, scrollIntoView){
11355 if(v !== undefined && v !== null){
11356 var r = this.findRecord(this.valueField || this.displayField, v);
11358 this.select(this.store.indexOf(r), scrollIntoView);
11366 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11367 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11368 * @param {Number} index The zero-based index of the list item to select
11369 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11370 * selected item if it is not currently in view (defaults to true)
11372 select : function(index, scrollIntoView){
11373 this.selectedIndex = index;
11374 this.view.select(index);
11375 if(scrollIntoView !== false){
11376 var el = this.view.getNode(index);
11377 if(el && !this.multiple && !this.tickable){
11378 this.list.scrollChildIntoView(el, false);
11384 selectNext : function(){
11385 var ct = this.store.getCount();
11387 if(this.selectedIndex == -1){
11389 }else if(this.selectedIndex < ct-1){
11390 this.select(this.selectedIndex+1);
11396 selectPrev : function(){
11397 var ct = this.store.getCount();
11399 if(this.selectedIndex == -1){
11401 }else if(this.selectedIndex != 0){
11402 this.select(this.selectedIndex-1);
11408 onKeyUp : function(e){
11409 if(this.editable !== false && !e.isSpecialKey()){
11410 this.lastKey = e.getKey();
11411 this.dqTask.delay(this.queryDelay);
11416 validateBlur : function(){
11417 return !this.list || !this.list.isVisible();
11421 initQuery : function(){
11422 this.doQuery(this.getRawValue());
11426 doForce : function(){
11427 if(this.inputEl().dom.value.length > 0){
11428 this.inputEl().dom.value =
11429 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11435 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
11436 * query allowing the query action to be canceled if needed.
11437 * @param {String} query The SQL query to execute
11438 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11439 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
11440 * saved in the current store (defaults to false)
11442 doQuery : function(q, forceAll){
11444 if(q === undefined || q === null){
11449 forceAll: forceAll,
11453 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11458 forceAll = qe.forceAll;
11459 if(forceAll === true || (q.length >= this.minChars)){
11461 this.hasQuery = true;
11463 if(this.lastQuery != q || this.alwaysQuery){
11464 this.lastQuery = q;
11465 if(this.mode == 'local'){
11466 this.selectedIndex = -1;
11468 this.store.clearFilter();
11470 this.store.filter(this.displayField, q);
11474 this.store.baseParams[this.queryParam] = q;
11476 var options = {params : this.getParams(q)};
11479 options.add = true;
11480 options.params.start = this.page * this.pageSize;
11483 this.store.load(options);
11485 * this code will make the page width larger, at the beginning, the list not align correctly,
11486 * we should expand the list on onLoad
11487 * so command out it
11492 this.selectedIndex = -1;
11497 this.loadNext = false;
11501 getParams : function(q){
11503 //p[this.queryParam] = q;
11507 p.limit = this.pageSize;
11513 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11515 collapse : function(){
11516 if(!this.isExpanded()){
11524 this.cancelBtn.hide();
11525 this.trigger.show();
11528 Roo.get(document).un('mousedown', this.collapseIf, this);
11529 Roo.get(document).un('mousewheel', this.collapseIf, this);
11530 if (!this.editable) {
11531 Roo.get(document).un('keydown', this.listKeyPress, this);
11533 this.fireEvent('collapse', this);
11537 collapseIf : function(e){
11538 var in_combo = e.within(this.el);
11539 var in_list = e.within(this.list);
11540 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11542 if (in_combo || in_list || is_list) {
11543 //e.stopPropagation();
11548 this.onTickableFooterButtonClick(e, false, false);
11556 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11558 expand : function(){
11560 if(this.isExpanded() || !this.hasFocus){
11564 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11565 this.list.setWidth(lw);
11570 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11571 this.list.setWidth(lw);
11575 this.restrictHeight();
11579 this.tickItems = Roo.apply([], this.item);
11582 this.cancelBtn.show();
11583 this.trigger.hide();
11587 Roo.get(document).on('mousedown', this.collapseIf, this);
11588 Roo.get(document).on('mousewheel', this.collapseIf, this);
11589 if (!this.editable) {
11590 Roo.get(document).on('keydown', this.listKeyPress, this);
11593 this.fireEvent('expand', this);
11597 // Implements the default empty TriggerField.onTriggerClick function
11598 onTriggerClick : function(e)
11600 Roo.log('trigger click');
11602 if(this.disabled || !this.triggerList){
11607 this.loadNext = false;
11609 if(this.isExpanded()){
11611 if (!this.blockFocus) {
11612 this.inputEl().focus();
11616 this.hasFocus = true;
11617 if(this.triggerAction == 'all') {
11618 this.doQuery(this.allQuery, true);
11620 this.doQuery(this.getRawValue());
11622 if (!this.blockFocus) {
11623 this.inputEl().focus();
11628 onTickableTriggerClick : function(e)
11635 this.loadNext = false;
11636 this.hasFocus = true;
11638 if(this.triggerAction == 'all') {
11639 this.doQuery(this.allQuery, true);
11641 this.doQuery(this.getRawValue());
11645 onSearchFieldClick : function(e)
11647 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11652 this.loadNext = false;
11653 this.hasFocus = true;
11655 if(this.triggerAction == 'all') {
11656 this.doQuery(this.allQuery, true);
11658 this.doQuery(this.getRawValue());
11662 listKeyPress : function(e)
11664 //Roo.log('listkeypress');
11665 // scroll to first matching element based on key pres..
11666 if (e.isSpecialKey()) {
11669 var k = String.fromCharCode(e.getKey()).toUpperCase();
11672 var csel = this.view.getSelectedNodes();
11673 var cselitem = false;
11675 var ix = this.view.indexOf(csel[0]);
11676 cselitem = this.store.getAt(ix);
11677 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11683 this.store.each(function(v) {
11685 // start at existing selection.
11686 if (cselitem.id == v.id) {
11692 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11693 match = this.store.indexOf(v);
11699 if (match === false) {
11700 return true; // no more action?
11703 this.view.select(match);
11704 var sn = Roo.get(this.view.getSelectedNodes()[0])
11705 //sn.scrollIntoView(sn.dom.parentNode, false);
11708 onViewScroll : function(e, t){
11710 if(this.view.el.getScroll().top == 0 ||this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
11714 this.hasQuery = true;
11716 this.loading = this.list.select('.loading', true).first();
11718 if(this.loading === null){
11719 this.list.createChild({
11721 cls: 'loading select2-more-results select2-active',
11722 html: 'Loading more results...'
11725 this.loading = this.list.select('.loading', true).first();
11727 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11729 this.loading.hide();
11732 this.loading.show();
11737 this.loadNext = true;
11739 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11744 addItem : function(o)
11746 var dv = ''; // display value
11748 if (this.displayField) {
11749 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11751 // this is an error condition!!!
11752 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11759 var choice = this.choices.createChild({
11761 cls: 'select2-search-choice',
11770 cls: 'select2-search-choice-close',
11775 }, this.searchField);
11777 var close = choice.select('a.select2-search-choice-close', true).first()
11779 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11787 this.inputEl().dom.value = '';
11791 onRemoveItem : function(e, _self, o)
11793 e.preventDefault();
11794 var index = this.item.indexOf(o.data) * 1;
11797 Roo.log('not this item?!');
11801 this.item.splice(index, 1);
11806 this.fireEvent('remove', this, e);
11810 syncValue : function()
11812 if(!this.item.length){
11819 Roo.each(this.item, function(i){
11820 if(_this.valueField){
11821 value.push(i[_this.valueField]);
11828 this.value = value.join(',');
11830 if(this.hiddenField){
11831 this.hiddenField.dom.value = this.value;
11835 clearItem : function()
11837 if(!this.multiple){
11843 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11850 inputEl: function ()
11853 return this.searchField;
11855 return this.el.select('input.form-control',true).first();
11859 onTickableFooterButtonClick : function(e, btn, el)
11861 e.preventDefault();
11863 if(btn && btn.name == 'cancel'){
11864 this.tickItems = Roo.apply([], this.item);
11873 Roo.each(this.tickItems, function(o){
11884 * @cfg {Boolean} grow
11888 * @cfg {Number} growMin
11892 * @cfg {Number} growMax
11902 * Ext JS Library 1.1.1
11903 * Copyright(c) 2006-2007, Ext JS, LLC.
11905 * Originally Released Under LGPL - original licence link has changed is not relivant.
11908 * <script type="text/javascript">
11913 * @extends Roo.util.Observable
11914 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11915 * This class also supports single and multi selection modes. <br>
11916 * Create a data model bound view:
11918 var store = new Roo.data.Store(...);
11920 var view = new Roo.View({
11922 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11924 singleSelect: true,
11925 selectedClass: "ydataview-selected",
11929 // listen for node click?
11930 view.on("click", function(vw, index, node, e){
11931 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
11935 dataModel.load("foobar.xml");
11937 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
11939 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
11940 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
11942 * Note: old style constructor is still suported (container, template, config)
11945 * Create a new View
11946 * @param {Object} config The config object
11949 Roo.View = function(config, depreciated_tpl, depreciated_config){
11951 this.parent = false;
11953 if (typeof(depreciated_tpl) == 'undefined') {
11954 // new way.. - universal constructor.
11955 Roo.apply(this, config);
11956 this.el = Roo.get(this.el);
11959 this.el = Roo.get(config);
11960 this.tpl = depreciated_tpl;
11961 Roo.apply(this, depreciated_config);
11963 this.wrapEl = this.el.wrap().wrap();
11964 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
11967 if(typeof(this.tpl) == "string"){
11968 this.tpl = new Roo.Template(this.tpl);
11970 // support xtype ctors..
11971 this.tpl = new Roo.factory(this.tpl, Roo);
11975 this.tpl.compile();
11980 * @event beforeclick
11981 * Fires before a click is processed. Returns false to cancel the default action.
11982 * @param {Roo.View} this
11983 * @param {Number} index The index of the target node
11984 * @param {HTMLElement} node The target node
11985 * @param {Roo.EventObject} e The raw event object
11987 "beforeclick" : true,
11990 * Fires when a template node is clicked.
11991 * @param {Roo.View} this
11992 * @param {Number} index The index of the target node
11993 * @param {HTMLElement} node The target node
11994 * @param {Roo.EventObject} e The raw event object
11999 * Fires when a template node is double clicked.
12000 * @param {Roo.View} this
12001 * @param {Number} index The index of the target node
12002 * @param {HTMLElement} node The target node
12003 * @param {Roo.EventObject} e The raw event object
12007 * @event contextmenu
12008 * Fires when a template node is right clicked.
12009 * @param {Roo.View} this
12010 * @param {Number} index The index of the target node
12011 * @param {HTMLElement} node The target node
12012 * @param {Roo.EventObject} e The raw event object
12014 "contextmenu" : true,
12016 * @event selectionchange
12017 * Fires when the selected nodes change.
12018 * @param {Roo.View} this
12019 * @param {Array} selections Array of the selected nodes
12021 "selectionchange" : true,
12024 * @event beforeselect
12025 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12026 * @param {Roo.View} this
12027 * @param {HTMLElement} node The node to be selected
12028 * @param {Array} selections Array of currently selected nodes
12030 "beforeselect" : true,
12032 * @event preparedata
12033 * Fires on every row to render, to allow you to change the data.
12034 * @param {Roo.View} this
12035 * @param {Object} data to be rendered (change this)
12037 "preparedata" : true
12045 "click": this.onClick,
12046 "dblclick": this.onDblClick,
12047 "contextmenu": this.onContextMenu,
12051 this.selections = [];
12053 this.cmp = new Roo.CompositeElementLite([]);
12055 this.store = Roo.factory(this.store, Roo.data);
12056 this.setStore(this.store, true);
12059 if ( this.footer && this.footer.xtype) {
12061 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12063 this.footer.dataSource = this.store
12064 this.footer.container = fctr;
12065 this.footer = Roo.factory(this.footer, Roo);
12066 fctr.insertFirst(this.el);
12068 // this is a bit insane - as the paging toolbar seems to detach the el..
12069 // dom.parentNode.parentNode.parentNode
12070 // they get detached?
12074 Roo.View.superclass.constructor.call(this);
12079 Roo.extend(Roo.View, Roo.util.Observable, {
12082 * @cfg {Roo.data.Store} store Data store to load data from.
12087 * @cfg {String|Roo.Element} el The container element.
12092 * @cfg {String|Roo.Template} tpl The template used by this View
12096 * @cfg {String} dataName the named area of the template to use as the data area
12097 * Works with domtemplates roo-name="name"
12101 * @cfg {String} selectedClass The css class to add to selected nodes
12103 selectedClass : "x-view-selected",
12105 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12110 * @cfg {String} text to display on mask (default Loading)
12114 * @cfg {Boolean} multiSelect Allow multiple selection
12116 multiSelect : false,
12118 * @cfg {Boolean} singleSelect Allow single selection
12120 singleSelect: false,
12123 * @cfg {Boolean} toggleSelect - selecting
12125 toggleSelect : false,
12128 * @cfg {Boolean} tickable - selecting
12133 * Returns the element this view is bound to.
12134 * @return {Roo.Element}
12136 getEl : function(){
12137 return this.wrapEl;
12143 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12145 refresh : function(){
12146 Roo.log('refresh');
12149 // if we are using something like 'domtemplate', then
12150 // the what gets used is:
12151 // t.applySubtemplate(NAME, data, wrapping data..)
12152 // the outer template then get' applied with
12153 // the store 'extra data'
12154 // and the body get's added to the
12155 // roo-name="data" node?
12156 // <span class='roo-tpl-{name}'></span> ?????
12160 this.clearSelections();
12161 this.el.update("");
12163 var records = this.store.getRange();
12164 if(records.length < 1) {
12166 // is this valid?? = should it render a template??
12168 this.el.update(this.emptyText);
12172 if (this.dataName) {
12173 this.el.update(t.apply(this.store.meta)); //????
12174 el = this.el.child('.roo-tpl-' + this.dataName);
12177 for(var i = 0, len = records.length; i < len; i++){
12178 var data = this.prepareData(records[i].data, i, records[i]);
12179 this.fireEvent("preparedata", this, data, i, records[i]);
12181 var d = Roo.apply({}, data);
12184 Roo.apply(d, {'roo-id' : Roo.id()});
12188 Roo.each(this.parent.item, function(item){
12189 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12192 Roo.apply(d, {'roo-data-checked' : 'checked'});
12196 html[html.length] = Roo.util.Format.trim(
12198 t.applySubtemplate(this.dataName, d, this.store.meta) :
12205 el.update(html.join(""));
12206 this.nodes = el.dom.childNodes;
12207 this.updateIndexes(0);
12212 * Function to override to reformat the data that is sent to
12213 * the template for each node.
12214 * DEPRICATED - use the preparedata event handler.
12215 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12216 * a JSON object for an UpdateManager bound view).
12218 prepareData : function(data, index, record)
12220 this.fireEvent("preparedata", this, data, index, record);
12224 onUpdate : function(ds, record){
12225 Roo.log('on update');
12226 this.clearSelections();
12227 var index = this.store.indexOf(record);
12228 var n = this.nodes[index];
12229 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12230 n.parentNode.removeChild(n);
12231 this.updateIndexes(index, index);
12237 onAdd : function(ds, records, index)
12239 Roo.log(['on Add', ds, records, index] );
12240 this.clearSelections();
12241 if(this.nodes.length == 0){
12245 var n = this.nodes[index];
12246 for(var i = 0, len = records.length; i < len; i++){
12247 var d = this.prepareData(records[i].data, i, records[i]);
12249 this.tpl.insertBefore(n, d);
12252 this.tpl.append(this.el, d);
12255 this.updateIndexes(index);
12258 onRemove : function(ds, record, index){
12259 Roo.log('onRemove');
12260 this.clearSelections();
12261 var el = this.dataName ?
12262 this.el.child('.roo-tpl-' + this.dataName) :
12265 el.dom.removeChild(this.nodes[index]);
12266 this.updateIndexes(index);
12270 * Refresh an individual node.
12271 * @param {Number} index
12273 refreshNode : function(index){
12274 this.onUpdate(this.store, this.store.getAt(index));
12277 updateIndexes : function(startIndex, endIndex){
12278 var ns = this.nodes;
12279 startIndex = startIndex || 0;
12280 endIndex = endIndex || ns.length - 1;
12281 for(var i = startIndex; i <= endIndex; i++){
12282 ns[i].nodeIndex = i;
12287 * Changes the data store this view uses and refresh the view.
12288 * @param {Store} store
12290 setStore : function(store, initial){
12291 if(!initial && this.store){
12292 this.store.un("datachanged", this.refresh);
12293 this.store.un("add", this.onAdd);
12294 this.store.un("remove", this.onRemove);
12295 this.store.un("update", this.onUpdate);
12296 this.store.un("clear", this.refresh);
12297 this.store.un("beforeload", this.onBeforeLoad);
12298 this.store.un("load", this.onLoad);
12299 this.store.un("loadexception", this.onLoad);
12303 store.on("datachanged", this.refresh, this);
12304 store.on("add", this.onAdd, this);
12305 store.on("remove", this.onRemove, this);
12306 store.on("update", this.onUpdate, this);
12307 store.on("clear", this.refresh, this);
12308 store.on("beforeload", this.onBeforeLoad, this);
12309 store.on("load", this.onLoad, this);
12310 store.on("loadexception", this.onLoad, this);
12318 * onbeforeLoad - masks the loading area.
12321 onBeforeLoad : function(store,opts)
12323 Roo.log('onBeforeLoad');
12325 this.el.update("");
12327 this.el.mask(this.mask ? this.mask : "Loading" );
12329 onLoad : function ()
12336 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12337 * @param {HTMLElement} node
12338 * @return {HTMLElement} The template node
12340 findItemFromChild : function(node){
12341 var el = this.dataName ?
12342 this.el.child('.roo-tpl-' + this.dataName,true) :
12345 if(!node || node.parentNode == el){
12348 var p = node.parentNode;
12349 while(p && p != el){
12350 if(p.parentNode == el){
12359 onClick : function(e){
12360 var item = this.findItemFromChild(e.getTarget());
12362 var index = this.indexOf(item);
12363 if(this.onItemClick(item, index, e) !== false){
12364 this.fireEvent("click", this, index, item, e);
12367 this.clearSelections();
12372 onContextMenu : function(e){
12373 var item = this.findItemFromChild(e.getTarget());
12375 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12380 onDblClick : function(e){
12381 var item = this.findItemFromChild(e.getTarget());
12383 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12387 onItemClick : function(item, index, e)
12389 if(this.fireEvent("beforeclick", this, index, item, e) === false){
12392 if (this.toggleSelect) {
12393 var m = this.isSelected(item) ? 'unselect' : 'select';
12396 _t[m](item, true, false);
12399 if(this.multiSelect || this.singleSelect){
12400 if(this.multiSelect && e.shiftKey && this.lastSelection){
12401 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12403 this.select(item, this.multiSelect && e.ctrlKey);
12404 this.lastSelection = item;
12407 if(!this.tickable){
12408 e.preventDefault();
12416 * Get the number of selected nodes.
12419 getSelectionCount : function(){
12420 return this.selections.length;
12424 * Get the currently selected nodes.
12425 * @return {Array} An array of HTMLElements
12427 getSelectedNodes : function(){
12428 return this.selections;
12432 * Get the indexes of the selected nodes.
12435 getSelectedIndexes : function(){
12436 var indexes = [], s = this.selections;
12437 for(var i = 0, len = s.length; i < len; i++){
12438 indexes.push(s[i].nodeIndex);
12444 * Clear all selections
12445 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12447 clearSelections : function(suppressEvent){
12448 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12449 this.cmp.elements = this.selections;
12450 this.cmp.removeClass(this.selectedClass);
12451 this.selections = [];
12452 if(!suppressEvent){
12453 this.fireEvent("selectionchange", this, this.selections);
12459 * Returns true if the passed node is selected
12460 * @param {HTMLElement/Number} node The node or node index
12461 * @return {Boolean}
12463 isSelected : function(node){
12464 var s = this.selections;
12468 node = this.getNode(node);
12469 return s.indexOf(node) !== -1;
12474 * @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
12475 * @param {Boolean} keepExisting (optional) true to keep existing selections
12476 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12478 select : function(nodeInfo, keepExisting, suppressEvent){
12479 if(nodeInfo instanceof Array){
12481 this.clearSelections(true);
12483 for(var i = 0, len = nodeInfo.length; i < len; i++){
12484 this.select(nodeInfo[i], true, true);
12488 var node = this.getNode(nodeInfo);
12489 if(!node || this.isSelected(node)){
12490 return; // already selected.
12493 this.clearSelections(true);
12495 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12496 Roo.fly(node).addClass(this.selectedClass);
12497 this.selections.push(node);
12498 if(!suppressEvent){
12499 this.fireEvent("selectionchange", this, this.selections);
12507 * @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
12508 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12509 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12511 unselect : function(nodeInfo, keepExisting, suppressEvent)
12513 if(nodeInfo instanceof Array){
12514 Roo.each(this.selections, function(s) {
12515 this.unselect(s, nodeInfo);
12519 var node = this.getNode(nodeInfo);
12520 if(!node || !this.isSelected(node)){
12521 Roo.log("not selected");
12522 return; // not selected.
12526 Roo.each(this.selections, function(s) {
12528 Roo.fly(node).removeClass(this.selectedClass);
12535 this.selections= ns;
12536 this.fireEvent("selectionchange", this, this.selections);
12540 * Gets a template node.
12541 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12542 * @return {HTMLElement} The node or null if it wasn't found
12544 getNode : function(nodeInfo){
12545 if(typeof nodeInfo == "string"){
12546 return document.getElementById(nodeInfo);
12547 }else if(typeof nodeInfo == "number"){
12548 return this.nodes[nodeInfo];
12554 * Gets a range template nodes.
12555 * @param {Number} startIndex
12556 * @param {Number} endIndex
12557 * @return {Array} An array of nodes
12559 getNodes : function(start, end){
12560 var ns = this.nodes;
12561 start = start || 0;
12562 end = typeof end == "undefined" ? ns.length - 1 : end;
12565 for(var i = start; i <= end; i++){
12569 for(var i = start; i >= end; i--){
12577 * Finds the index of the passed node
12578 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12579 * @return {Number} The index of the node or -1
12581 indexOf : function(node){
12582 node = this.getNode(node);
12583 if(typeof node.nodeIndex == "number"){
12584 return node.nodeIndex;
12586 var ns = this.nodes;
12587 for(var i = 0, len = ns.length; i < len; i++){
12598 * based on jquery fullcalendar
12602 Roo.bootstrap = Roo.bootstrap || {};
12604 * @class Roo.bootstrap.Calendar
12605 * @extends Roo.bootstrap.Component
12606 * Bootstrap Calendar class
12607 * @cfg {Boolean} loadMask (true|false) default false
12608 * @cfg {Object} header generate the user specific header of the calendar, default false
12611 * Create a new Container
12612 * @param {Object} config The config object
12617 Roo.bootstrap.Calendar = function(config){
12618 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12622 * Fires when a date is selected
12623 * @param {DatePicker} this
12624 * @param {Date} date The selected date
12628 * @event monthchange
12629 * Fires when the displayed month changes
12630 * @param {DatePicker} this
12631 * @param {Date} date The selected month
12633 'monthchange': true,
12635 * @event evententer
12636 * Fires when mouse over an event
12637 * @param {Calendar} this
12638 * @param {event} Event
12640 'evententer': true,
12642 * @event eventleave
12643 * Fires when the mouse leaves an
12644 * @param {Calendar} this
12647 'eventleave': true,
12649 * @event eventclick
12650 * Fires when the mouse click an
12651 * @param {Calendar} this
12660 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
12663 * @cfg {Number} startDay
12664 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12672 getAutoCreate : function(){
12675 var fc_button = function(name, corner, style, content ) {
12676 return Roo.apply({},{
12678 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
12680 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12683 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12694 style : 'width:100%',
12701 cls : 'fc-header-left',
12703 fc_button('prev', 'left', 'arrow', '‹' ),
12704 fc_button('next', 'right', 'arrow', '›' ),
12705 { tag: 'span', cls: 'fc-header-space' },
12706 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
12714 cls : 'fc-header-center',
12718 cls: 'fc-header-title',
12721 html : 'month / year'
12729 cls : 'fc-header-right',
12731 /* fc_button('month', 'left', '', 'month' ),
12732 fc_button('week', '', '', 'week' ),
12733 fc_button('day', 'right', '', 'day' )
12745 header = this.header;
12748 var cal_heads = function() {
12750 // fixme - handle this.
12752 for (var i =0; i < Date.dayNames.length; i++) {
12753 var d = Date.dayNames[i];
12756 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12757 html : d.substring(0,3)
12761 ret[0].cls += ' fc-first';
12762 ret[6].cls += ' fc-last';
12765 var cal_cell = function(n) {
12768 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12773 cls: 'fc-day-number',
12777 cls: 'fc-day-content',
12781 style: 'position: relative;' // height: 17px;
12793 var cal_rows = function() {
12796 for (var r = 0; r < 6; r++) {
12803 for (var i =0; i < Date.dayNames.length; i++) {
12804 var d = Date.dayNames[i];
12805 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12808 row.cn[0].cls+=' fc-first';
12809 row.cn[0].cn[0].style = 'min-height:90px';
12810 row.cn[6].cls+=' fc-last';
12814 ret[0].cls += ' fc-first';
12815 ret[4].cls += ' fc-prev-last';
12816 ret[5].cls += ' fc-last';
12823 cls: 'fc-border-separate',
12824 style : 'width:100%',
12832 cls : 'fc-first fc-last',
12850 cls : 'fc-content',
12851 style : "position: relative;",
12854 cls : 'fc-view fc-view-month fc-grid',
12855 style : 'position: relative',
12856 unselectable : 'on',
12859 cls : 'fc-event-container',
12860 style : 'position:absolute;z-index:8;top:0;left:0;'
12878 initEvents : function()
12881 throw "can not find store for calendar";
12887 style: "text-align:center",
12891 style: "background-color:white;width:50%;margin:250 auto",
12895 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12906 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12908 var size = this.el.select('.fc-content', true).first().getSize();
12909 this.maskEl.setSize(size.width, size.height);
12910 this.maskEl.enableDisplayMode("block");
12911 if(!this.loadMask){
12912 this.maskEl.hide();
12915 this.store = Roo.factory(this.store, Roo.data);
12916 this.store.on('load', this.onLoad, this);
12917 this.store.on('beforeload', this.onBeforeLoad, this);
12921 this.cells = this.el.select('.fc-day',true);
12922 //Roo.log(this.cells);
12923 this.textNodes = this.el.query('.fc-day-number');
12924 this.cells.addClassOnOver('fc-state-hover');
12926 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12927 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12928 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12929 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12931 this.on('monthchange', this.onMonthChange, this);
12933 this.update(new Date().clearTime());
12936 resize : function() {
12937 var sz = this.el.getSize();
12939 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
12940 this.el.select('.fc-day-content div',true).setHeight(34);
12945 showPrevMonth : function(e){
12946 this.update(this.activeDate.add("mo", -1));
12948 showToday : function(e){
12949 this.update(new Date().clearTime());
12952 showNextMonth : function(e){
12953 this.update(this.activeDate.add("mo", 1));
12957 showPrevYear : function(){
12958 this.update(this.activeDate.add("y", -1));
12962 showNextYear : function(){
12963 this.update(this.activeDate.add("y", 1));
12968 update : function(date)
12970 var vd = this.activeDate;
12971 this.activeDate = date;
12972 // if(vd && this.el){
12973 // var t = date.getTime();
12974 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
12975 // Roo.log('using add remove');
12977 // this.fireEvent('monthchange', this, date);
12979 // this.cells.removeClass("fc-state-highlight");
12980 // this.cells.each(function(c){
12981 // if(c.dateValue == t){
12982 // c.addClass("fc-state-highlight");
12983 // setTimeout(function(){
12984 // try{c.dom.firstChild.focus();}catch(e){}
12994 var days = date.getDaysInMonth();
12996 var firstOfMonth = date.getFirstDateOfMonth();
12997 var startingPos = firstOfMonth.getDay()-this.startDay;
12999 if(startingPos < this.startDay){
13003 var pm = date.add(Date.MONTH, -1);
13004 var prevStart = pm.getDaysInMonth()-startingPos;
13006 this.cells = this.el.select('.fc-day',true);
13007 this.textNodes = this.el.query('.fc-day-number');
13008 this.cells.addClassOnOver('fc-state-hover');
13010 var cells = this.cells.elements;
13011 var textEls = this.textNodes;
13013 Roo.each(cells, function(cell){
13014 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13017 days += startingPos;
13019 // convert everything to numbers so it's fast
13020 var day = 86400000;
13021 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13024 //Roo.log(prevStart);
13026 var today = new Date().clearTime().getTime();
13027 var sel = date.clearTime().getTime();
13028 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13029 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13030 var ddMatch = this.disabledDatesRE;
13031 var ddText = this.disabledDatesText;
13032 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13033 var ddaysText = this.disabledDaysText;
13034 var format = this.format;
13036 var setCellClass = function(cal, cell){
13040 //Roo.log('set Cell Class');
13042 var t = d.getTime();
13046 cell.dateValue = t;
13048 cell.className += " fc-today";
13049 cell.className += " fc-state-highlight";
13050 cell.title = cal.todayText;
13053 // disable highlight in other month..
13054 //cell.className += " fc-state-highlight";
13059 cell.className = " fc-state-disabled";
13060 cell.title = cal.minText;
13064 cell.className = " fc-state-disabled";
13065 cell.title = cal.maxText;
13069 if(ddays.indexOf(d.getDay()) != -1){
13070 cell.title = ddaysText;
13071 cell.className = " fc-state-disabled";
13074 if(ddMatch && format){
13075 var fvalue = d.dateFormat(format);
13076 if(ddMatch.test(fvalue)){
13077 cell.title = ddText.replace("%0", fvalue);
13078 cell.className = " fc-state-disabled";
13082 if (!cell.initialClassName) {
13083 cell.initialClassName = cell.dom.className;
13086 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13091 for(; i < startingPos; i++) {
13092 textEls[i].innerHTML = (++prevStart);
13093 d.setDate(d.getDate()+1);
13095 cells[i].className = "fc-past fc-other-month";
13096 setCellClass(this, cells[i]);
13101 for(; i < days; i++){
13102 intDay = i - startingPos + 1;
13103 textEls[i].innerHTML = (intDay);
13104 d.setDate(d.getDate()+1);
13106 cells[i].className = ''; // "x-date-active";
13107 setCellClass(this, cells[i]);
13111 for(; i < 42; i++) {
13112 textEls[i].innerHTML = (++extraDays);
13113 d.setDate(d.getDate()+1);
13115 cells[i].className = "fc-future fc-other-month";
13116 setCellClass(this, cells[i]);
13119 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13121 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13123 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13124 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13126 if(totalRows != 6){
13127 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13128 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13131 this.fireEvent('monthchange', this, date);
13135 if(!this.internalRender){
13136 var main = this.el.dom.firstChild;
13137 var w = main.offsetWidth;
13138 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13139 Roo.fly(main).setWidth(w);
13140 this.internalRender = true;
13141 // opera does not respect the auto grow header center column
13142 // then, after it gets a width opera refuses to recalculate
13143 // without a second pass
13144 if(Roo.isOpera && !this.secondPass){
13145 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13146 this.secondPass = true;
13147 this.update.defer(10, this, [date]);
13154 findCell : function(dt) {
13155 dt = dt.clearTime().getTime();
13157 this.cells.each(function(c){
13158 //Roo.log("check " +c.dateValue + '?=' + dt);
13159 if(c.dateValue == dt){
13169 findCells : function(ev) {
13170 var s = ev.start.clone().clearTime().getTime();
13172 var e= ev.end.clone().clearTime().getTime();
13175 this.cells.each(function(c){
13176 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13178 if(c.dateValue > e){
13181 if(c.dateValue < s){
13190 // findBestRow: function(cells)
13194 // for (var i =0 ; i < cells.length;i++) {
13195 // ret = Math.max(cells[i].rows || 0,ret);
13202 addItem : function(ev)
13204 // look for vertical location slot in
13205 var cells = this.findCells(ev);
13207 // ev.row = this.findBestRow(cells);
13209 // work out the location.
13213 for(var i =0; i < cells.length; i++) {
13215 cells[i].row = cells[0].row;
13218 cells[i].row = cells[i].row + 1;
13228 if (crow.start.getY() == cells[i].getY()) {
13230 crow.end = cells[i];
13247 cells[0].events.push(ev);
13249 this.calevents.push(ev);
13252 clearEvents: function() {
13254 if(!this.calevents){
13258 Roo.each(this.cells.elements, function(c){
13264 Roo.each(this.calevents, function(e) {
13265 Roo.each(e.els, function(el) {
13266 el.un('mouseenter' ,this.onEventEnter, this);
13267 el.un('mouseleave' ,this.onEventLeave, this);
13272 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13278 renderEvents: function()
13282 this.cells.each(function(c) {
13291 if(c.row != c.events.length){
13292 r = 4 - (4 - (c.row - c.events.length));
13295 c.events = ev.slice(0, r);
13296 c.more = ev.slice(r);
13298 if(c.more.length && c.more.length == 1){
13299 c.events.push(c.more.pop());
13302 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13306 this.cells.each(function(c) {
13308 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13311 for (var e = 0; e < c.events.length; e++){
13312 var ev = c.events[e];
13313 var rows = ev.rows;
13315 for(var i = 0; i < rows.length; i++) {
13317 // how many rows should it span..
13320 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13321 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13323 unselectable : "on",
13326 cls: 'fc-event-inner',
13330 // cls: 'fc-event-time',
13331 // html : cells.length > 1 ? '' : ev.time
13335 cls: 'fc-event-title',
13336 html : String.format('{0}', ev.title)
13343 cls: 'ui-resizable-handle ui-resizable-e',
13344 html : '  '
13351 cfg.cls += ' fc-event-start';
13353 if ((i+1) == rows.length) {
13354 cfg.cls += ' fc-event-end';
13357 var ctr = _this.el.select('.fc-event-container',true).first();
13358 var cg = ctr.createChild(cfg);
13360 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13361 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13363 var r = (c.more.length) ? 1 : 0;
13364 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
13365 cg.setWidth(ebox.right - sbox.x -2);
13367 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13368 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13369 cg.on('click', _this.onEventClick, _this, ev);
13380 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13381 style : 'position: absolute',
13382 unselectable : "on",
13385 cls: 'fc-event-inner',
13389 cls: 'fc-event-title',
13397 cls: 'ui-resizable-handle ui-resizable-e',
13398 html : '  '
13404 var ctr = _this.el.select('.fc-event-container',true).first();
13405 var cg = ctr.createChild(cfg);
13407 var sbox = c.select('.fc-day-content',true).first().getBox();
13408 var ebox = c.select('.fc-day-content',true).first().getBox();
13410 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
13411 cg.setWidth(ebox.right - sbox.x -2);
13413 cg.on('click', _this.onMoreEventClick, _this, c.more);
13423 onEventEnter: function (e, el,event,d) {
13424 this.fireEvent('evententer', this, el, event);
13427 onEventLeave: function (e, el,event,d) {
13428 this.fireEvent('eventleave', this, el, event);
13431 onEventClick: function (e, el,event,d) {
13432 this.fireEvent('eventclick', this, el, event);
13435 onMonthChange: function () {
13439 onMoreEventClick: function(e, el, more)
13443 this.calpopover.placement = 'right';
13444 this.calpopover.setTitle('More');
13446 this.calpopover.setContent('');
13448 var ctr = this.calpopover.el.select('.popover-content', true).first();
13450 Roo.each(more, function(m){
13452 cls : 'fc-event-hori fc-event-draggable',
13455 var cg = ctr.createChild(cfg);
13457 cg.on('click', _this.onEventClick, _this, m);
13460 this.calpopover.show(el);
13465 onLoad: function ()
13467 this.calevents = [];
13470 if(this.store.getCount() > 0){
13471 this.store.data.each(function(d){
13474 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13475 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13476 time : d.data.start_time,
13477 title : d.data.title,
13478 description : d.data.description,
13479 venue : d.data.venue
13484 this.renderEvents();
13486 if(this.calevents.length && this.loadMask){
13487 this.maskEl.hide();
13491 onBeforeLoad: function()
13493 this.clearEvents();
13495 this.maskEl.show();
13509 * @class Roo.bootstrap.Popover
13510 * @extends Roo.bootstrap.Component
13511 * Bootstrap Popover class
13512 * @cfg {String} html contents of the popover (or false to use children..)
13513 * @cfg {String} title of popover (or false to hide)
13514 * @cfg {String} placement how it is placed
13515 * @cfg {String} trigger click || hover (or false to trigger manually)
13516 * @cfg {String} over what (parent or false to trigger manually.)
13519 * Create a new Popover
13520 * @param {Object} config The config object
13523 Roo.bootstrap.Popover = function(config){
13524 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13527 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
13529 title: 'Fill in a title',
13532 placement : 'right',
13533 trigger : 'hover', // hover
13537 can_build_overlaid : false,
13539 getChildContainer : function()
13541 return this.el.select('.popover-content',true).first();
13544 getAutoCreate : function(){
13545 Roo.log('make popover?');
13547 cls : 'popover roo-dynamic',
13548 style: 'display:block',
13554 cls : 'popover-inner',
13558 cls: 'popover-title',
13562 cls : 'popover-content',
13573 setTitle: function(str)
13575 this.el.select('.popover-title',true).first().dom.innerHTML = str;
13577 setContent: function(str)
13579 this.el.select('.popover-content',true).first().dom.innerHTML = str;
13581 // as it get's added to the bottom of the page.
13582 onRender : function(ct, position)
13584 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13586 var cfg = Roo.apply({}, this.getAutoCreate());
13590 cfg.cls += ' ' + this.cls;
13593 cfg.style = this.style;
13595 Roo.log("adding to ")
13596 this.el = Roo.get(document.body).createChild(cfg, position);
13602 initEvents : function()
13604 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13605 this.el.enableDisplayMode('block');
13607 if (this.over === false) {
13610 if (this.triggers === false) {
13613 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13614 var triggers = this.trigger ? this.trigger.split(' ') : [];
13615 Roo.each(triggers, function(trigger) {
13617 if (trigger == 'click') {
13618 on_el.on('click', this.toggle, this);
13619 } else if (trigger != 'manual') {
13620 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
13621 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13623 on_el.on(eventIn ,this.enter, this);
13624 on_el.on(eventOut, this.leave, this);
13635 toggle : function () {
13636 this.hoverState == 'in' ? this.leave() : this.enter();
13639 enter : function () {
13642 clearTimeout(this.timeout);
13644 this.hoverState = 'in'
13646 if (!this.delay || !this.delay.show) {
13651 this.timeout = setTimeout(function () {
13652 if (_t.hoverState == 'in') {
13655 }, this.delay.show)
13657 leave : function() {
13658 clearTimeout(this.timeout);
13660 this.hoverState = 'out'
13662 if (!this.delay || !this.delay.hide) {
13667 this.timeout = setTimeout(function () {
13668 if (_t.hoverState == 'out') {
13671 }, this.delay.hide)
13674 show : function (on_el)
13677 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13680 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13681 if (this.html !== false) {
13682 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13684 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13685 if (!this.title.length) {
13686 this.el.select('.popover-title',true).hide();
13689 var placement = typeof this.placement == 'function' ?
13690 this.placement.call(this, this.el, on_el) :
13693 var autoToken = /\s?auto?\s?/i;
13694 var autoPlace = autoToken.test(placement);
13696 placement = placement.replace(autoToken, '') || 'top';
13700 //this.el.setXY([0,0]);
13702 this.el.dom.style.display='block';
13703 this.el.addClass(placement);
13705 //this.el.appendTo(on_el);
13707 var p = this.getPosition();
13708 var box = this.el.getBox();
13713 var align = Roo.bootstrap.Popover.alignment[placement]
13714 this.el.alignTo(on_el, align[0],align[1]);
13715 //var arrow = this.el.select('.arrow',true).first();
13716 //arrow.set(align[2],
13718 this.el.addClass('in');
13719 this.hoverState = null;
13721 if (this.el.hasClass('fade')) {
13728 this.el.setXY([0,0]);
13729 this.el.removeClass('in');
13736 Roo.bootstrap.Popover.alignment = {
13737 'left' : ['r-l', [-10,0], 'right'],
13738 'right' : ['l-r', [10,0], 'left'],
13739 'bottom' : ['t-b', [0,10], 'top'],
13740 'top' : [ 'b-t', [0,-10], 'bottom']
13751 * @class Roo.bootstrap.Progress
13752 * @extends Roo.bootstrap.Component
13753 * Bootstrap Progress class
13754 * @cfg {Boolean} striped striped of the progress bar
13755 * @cfg {Boolean} active animated of the progress bar
13759 * Create a new Progress
13760 * @param {Object} config The config object
13763 Roo.bootstrap.Progress = function(config){
13764 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13767 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
13772 getAutoCreate : function(){
13780 cfg.cls += ' progress-striped';
13784 cfg.cls += ' active';
13803 * @class Roo.bootstrap.ProgressBar
13804 * @extends Roo.bootstrap.Component
13805 * Bootstrap ProgressBar class
13806 * @cfg {Number} aria_valuenow aria-value now
13807 * @cfg {Number} aria_valuemin aria-value min
13808 * @cfg {Number} aria_valuemax aria-value max
13809 * @cfg {String} label label for the progress bar
13810 * @cfg {String} panel (success | info | warning | danger )
13811 * @cfg {String} role role of the progress bar
13812 * @cfg {String} sr_only text
13816 * Create a new ProgressBar
13817 * @param {Object} config The config object
13820 Roo.bootstrap.ProgressBar = function(config){
13821 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13824 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
13828 aria_valuemax : 100,
13834 getAutoCreate : function()
13839 cls: 'progress-bar',
13840 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13852 cfg.role = this.role;
13855 if(this.aria_valuenow){
13856 cfg['aria-valuenow'] = this.aria_valuenow;
13859 if(this.aria_valuemin){
13860 cfg['aria-valuemin'] = this.aria_valuemin;
13863 if(this.aria_valuemax){
13864 cfg['aria-valuemax'] = this.aria_valuemax;
13867 if(this.label && !this.sr_only){
13868 cfg.html = this.label;
13872 cfg.cls += ' progress-bar-' + this.panel;
13878 update : function(aria_valuenow)
13880 this.aria_valuenow = aria_valuenow;
13882 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13897 * @class Roo.bootstrap.TabGroup
13898 * @extends Roo.bootstrap.Column
13899 * Bootstrap Column class
13900 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
13901 * @cfg {Boolean} carousel true to make the group behave like a carousel
13904 * Create a new TabGroup
13905 * @param {Object} config The config object
13908 Roo.bootstrap.TabGroup = function(config){
13909 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
13911 this.navId = Roo.id();
13914 Roo.bootstrap.TabGroup.register(this);
13918 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
13921 transition : false,
13923 getAutoCreate : function()
13925 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
13927 cfg.cls += ' tab-content';
13929 if (this.carousel) {
13930 cfg.cls += ' carousel slide';
13932 cls : 'carousel-inner'
13939 getChildContainer : function()
13941 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
13945 * register a Navigation item
13946 * @param {Roo.bootstrap.NavItem} the navitem to add
13948 register : function(item)
13950 this.tabs.push( item);
13951 item.navId = this.navId; // not really needed..
13955 getActivePanel : function()
13958 Roo.each(this.tabs, function(t) {
13968 getPanelByName : function(n)
13971 Roo.each(this.tabs, function(t) {
13972 if (t.tabId == n) {
13980 indexOfPanel : function(p)
13983 Roo.each(this.tabs, function(t,i) {
13984 if (t.tabId == p.tabId) {
13993 * show a specific panel
13994 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
13995 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
13997 showPanel : function (pan)
14000 if (typeof(pan) == 'number') {
14001 pan = this.tabs[pan];
14003 if (typeof(pan) == 'string') {
14004 pan = this.getPanelByName(pan);
14006 if (pan.tabId == this.getActivePanel().tabId) {
14009 var cur = this.getActivePanel();
14011 if (false === cur.fireEvent('beforedeactivate')) {
14015 if (this.carousel) {
14016 this.transition = true;
14017 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14018 var lr = dir == 'next' ? 'left' : 'right';
14019 pan.el.addClass(dir); // or prev
14020 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14021 cur.el.addClass(lr); // or right
14022 pan.el.addClass(lr);
14025 cur.el.on('transitionend', function() {
14026 Roo.log("trans end?");
14028 pan.el.removeClass([lr,dir]);
14029 pan.setActive(true);
14031 cur.el.removeClass([lr]);
14032 cur.setActive(false);
14034 _this.transition = false;
14036 }, this, { single: true } );
14040 cur.setActive(false);
14041 pan.setActive(true);
14045 showPanelNext : function()
14047 var i = this.indexOfPanel(this.getActivePanel());
14048 if (i > this.tabs.length) {
14051 this.showPanel(this.tabs[i+1]);
14053 showPanelPrev : function()
14055 var i = this.indexOfPanel(this.getActivePanel());
14059 this.showPanel(this.tabs[i-1]);
14070 Roo.apply(Roo.bootstrap.TabGroup, {
14074 * register a Navigation Group
14075 * @param {Roo.bootstrap.NavGroup} the navgroup to add
14077 register : function(navgrp)
14079 this.groups[navgrp.navId] = navgrp;
14083 * fetch a Navigation Group based on the navigation ID
14084 * if one does not exist , it will get created.
14085 * @param {string} the navgroup to add
14086 * @returns {Roo.bootstrap.NavGroup} the navgroup
14088 get: function(navId) {
14089 if (typeof(this.groups[navId]) == 'undefined') {
14090 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14092 return this.groups[navId] ;
14107 * @class Roo.bootstrap.TabPanel
14108 * @extends Roo.bootstrap.Component
14109 * Bootstrap TabPanel class
14110 * @cfg {Boolean} active panel active
14111 * @cfg {String} html panel content
14112 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14113 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14117 * Create a new TabPanel
14118 * @param {Object} config The config object
14121 Roo.bootstrap.TabPanel = function(config){
14122 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14126 * Fires when the active status changes
14127 * @param {Roo.bootstrap.TabPanel} this
14128 * @param {Boolean} state the new state
14133 * @event beforedeactivate
14134 * Fires before a tab is de-activated - can be used to do validation on a form.
14135 * @param {Roo.bootstrap.TabPanel} this
14136 * @return {Boolean} false if there is an error
14139 'beforedeactivate': true
14142 this.tabId = this.tabId || Roo.id();
14146 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
14153 getAutoCreate : function(){
14156 // item is needed for carousel - not sure if it has any effect otherwise
14157 cls: 'tab-pane item',
14158 html: this.html || ''
14162 cfg.cls += ' active';
14166 cfg.tabId = this.tabId;
14173 initEvents: function()
14175 Roo.log('-------- init events on tab panel ---------');
14177 var p = this.parent();
14178 this.navId = this.navId || p.navId;
14180 if (typeof(this.navId) != 'undefined') {
14181 // not really needed.. but just in case.. parent should be a NavGroup.
14182 var tg = Roo.bootstrap.TabGroup.get(this.navId);
14183 Roo.log(['register', tg, this]);
14189 onRender : function(ct, position)
14191 // Roo.log("Call onRender: " + this.xtype);
14193 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14201 setActive: function(state)
14203 Roo.log("panel - set active " + this.tabId + "=" + state);
14205 this.active = state;
14207 this.el.removeClass('active');
14209 } else if (!this.el.hasClass('active')) {
14210 this.el.addClass('active');
14212 this.fireEvent('changed', this, state);
14229 * @class Roo.bootstrap.DateField
14230 * @extends Roo.bootstrap.Input
14231 * Bootstrap DateField class
14232 * @cfg {Number} weekStart default 0
14233 * @cfg {Number} weekStart default 0
14234 * @cfg {Number} viewMode default empty, (months|years)
14235 * @cfg {Number} minViewMode default empty, (months|years)
14236 * @cfg {Number} startDate default -Infinity
14237 * @cfg {Number} endDate default Infinity
14238 * @cfg {Boolean} todayHighlight default false
14239 * @cfg {Boolean} todayBtn default false
14240 * @cfg {Boolean} calendarWeeks default false
14241 * @cfg {Object} daysOfWeekDisabled default empty
14243 * @cfg {Boolean} keyboardNavigation default true
14244 * @cfg {String} language default en
14247 * Create a new DateField
14248 * @param {Object} config The config object
14251 Roo.bootstrap.DateField = function(config){
14252 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14256 * Fires when this field show.
14257 * @param {Roo.bootstrap.DateField} this
14258 * @param {Mixed} date The date value
14263 * Fires when this field hide.
14264 * @param {Roo.bootstrap.DateField} this
14265 * @param {Mixed} date The date value
14270 * Fires when select a date.
14271 * @param {Roo.bootstrap.DateField} this
14272 * @param {Mixed} date The date value
14278 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
14281 * @cfg {String} format
14282 * The default date format string which can be overriden for localization support. The format must be
14283 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14287 * @cfg {String} altFormats
14288 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14289 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14291 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14299 todayHighlight : false,
14305 keyboardNavigation: true,
14307 calendarWeeks: false,
14309 startDate: -Infinity,
14313 daysOfWeekDisabled: [],
14317 UTCDate: function()
14319 return new Date(Date.UTC.apply(Date, arguments));
14322 UTCToday: function()
14324 var today = new Date();
14325 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14328 getDate: function() {
14329 var d = this.getUTCDate();
14330 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14333 getUTCDate: function() {
14337 setDate: function(d) {
14338 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14341 setUTCDate: function(d) {
14343 this.setValue(this.formatDate(this.date));
14346 onRender: function(ct, position)
14349 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14351 this.language = this.language || 'en';
14352 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14353 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14355 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14356 this.format = this.format || 'm/d/y';
14357 this.isInline = false;
14358 this.isInput = true;
14359 this.component = this.el.select('.add-on', true).first() || false;
14360 this.component = (this.component && this.component.length === 0) ? false : this.component;
14361 this.hasInput = this.component && this.inputEL().length;
14363 if (typeof(this.minViewMode === 'string')) {
14364 switch (this.minViewMode) {
14366 this.minViewMode = 1;
14369 this.minViewMode = 2;
14372 this.minViewMode = 0;
14377 if (typeof(this.viewMode === 'string')) {
14378 switch (this.viewMode) {
14391 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14393 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14395 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14397 this.picker().on('mousedown', this.onMousedown, this);
14398 this.picker().on('click', this.onClick, this);
14400 this.picker().addClass('datepicker-dropdown');
14402 this.startViewMode = this.viewMode;
14405 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14406 if(!this.calendarWeeks){
14411 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14412 v.attr('colspan', function(i, val){
14413 return parseInt(val) + 1;
14418 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14420 this.setStartDate(this.startDate);
14421 this.setEndDate(this.endDate);
14423 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14430 if(this.isInline) {
14435 picker : function()
14437 return this.pickerEl;
14438 // return this.el.select('.datepicker', true).first();
14441 fillDow: function()
14443 var dowCnt = this.weekStart;
14452 if(this.calendarWeeks){
14460 while (dowCnt < this.weekStart + 7) {
14464 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14468 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14471 fillMonths: function()
14474 var months = this.picker().select('>.datepicker-months td', true).first();
14476 months.dom.innerHTML = '';
14482 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14485 months.createChild(month);
14493 this.date = (typeof(this.date) === 'undefined' || !this.date.length) ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
14495 if (this.date < this.startDate) {
14496 this.viewDate = new Date(this.startDate);
14497 } else if (this.date > this.endDate) {
14498 this.viewDate = new Date(this.endDate);
14500 this.viewDate = new Date(this.date);
14508 var d = new Date(this.viewDate),
14509 year = d.getUTCFullYear(),
14510 month = d.getUTCMonth(),
14511 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14512 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14513 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14514 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14515 currentDate = this.date && this.date.valueOf(),
14516 today = this.UTCToday();
14518 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14520 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14522 // this.picker.select('>tfoot th.today').
14523 // .text(dates[this.language].today)
14524 // .toggle(this.todayBtn !== false);
14526 this.updateNavArrows();
14529 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14531 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14533 prevMonth.setUTCDate(day);
14535 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14537 var nextMonth = new Date(prevMonth);
14539 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14541 nextMonth = nextMonth.valueOf();
14543 var fillMonths = false;
14545 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14547 while(prevMonth.valueOf() < nextMonth) {
14550 if (prevMonth.getUTCDay() === this.weekStart) {
14552 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14560 if(this.calendarWeeks){
14561 // ISO 8601: First week contains first thursday.
14562 // ISO also states week starts on Monday, but we can be more abstract here.
14564 // Start of current week: based on weekstart/current date
14565 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14566 // Thursday of this week
14567 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14568 // First Thursday of year, year from thursday
14569 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14570 // Calendar week: ms between thursdays, div ms per day, div 7 days
14571 calWeek = (th - yth) / 864e5 / 7 + 1;
14573 fillMonths.cn.push({
14581 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14583 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14586 if (this.todayHighlight &&
14587 prevMonth.getUTCFullYear() == today.getFullYear() &&
14588 prevMonth.getUTCMonth() == today.getMonth() &&
14589 prevMonth.getUTCDate() == today.getDate()) {
14590 clsName += ' today';
14593 if (currentDate && prevMonth.valueOf() === currentDate) {
14594 clsName += ' active';
14597 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14598 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14599 clsName += ' disabled';
14602 fillMonths.cn.push({
14604 cls: 'day ' + clsName,
14605 html: prevMonth.getDate()
14608 prevMonth.setDate(prevMonth.getDate()+1);
14611 var currentYear = this.date && this.date.getUTCFullYear();
14612 var currentMonth = this.date && this.date.getUTCMonth();
14614 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14616 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14617 v.removeClass('active');
14619 if(currentYear === year && k === currentMonth){
14620 v.addClass('active');
14623 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14624 v.addClass('disabled');
14630 year = parseInt(year/10, 10) * 10;
14632 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14634 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14637 for (var i = -1; i < 11; i++) {
14638 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14640 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14648 showMode: function(dir)
14651 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14653 Roo.each(this.picker().select('>div',true).elements, function(v){
14654 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14657 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14662 if(this.isInline) return;
14664 this.picker().removeClass(['bottom', 'top']);
14666 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14668 * place to the top of element!
14672 this.picker().addClass('top');
14673 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
14678 this.picker().addClass('bottom');
14680 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
14683 parseDate : function(value)
14685 if(!value || value instanceof Date){
14688 var v = Date.parseDate(value, this.format);
14689 if (!v && this.useIso) {
14690 v = Date.parseDate(value, 'Y-m-d');
14692 if(!v && this.altFormats){
14693 if(!this.altFormatsArray){
14694 this.altFormatsArray = this.altFormats.split("|");
14696 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14697 v = Date.parseDate(value, this.altFormatsArray[i]);
14703 formatDate : function(date, fmt)
14705 return (!date || !(date instanceof Date)) ?
14706 date : date.dateFormat(fmt || this.format);
14709 onFocus : function()
14711 Roo.bootstrap.DateField.superclass.onFocus.call(this);
14715 onBlur : function()
14717 Roo.bootstrap.DateField.superclass.onBlur.call(this);
14719 var d = this.inputEl().getValue();
14728 this.picker().show();
14732 this.fireEvent('show', this, this.date);
14737 if(this.isInline) return;
14738 this.picker().hide();
14739 this.viewMode = this.startViewMode;
14742 this.fireEvent('hide', this, this.date);
14746 onMousedown: function(e)
14748 e.stopPropagation();
14749 e.preventDefault();
14754 Roo.bootstrap.DateField.superclass.keyup.call(this);
14758 setValue: function(v)
14760 var d = new Date(v);
14762 if(isNaN(d.getTime())){
14767 v = this.formatDate(d);
14769 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14771 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14775 this.fireEvent('select', this, this.date);
14779 getValue: function()
14781 return this.formatDate(this.date);
14784 fireKey: function(e)
14786 if (!this.picker().isVisible()){
14787 if (e.keyCode == 27) // allow escape to hide and re-show picker
14792 var dateChanged = false,
14794 newDate, newViewDate;
14799 e.preventDefault();
14803 if (!this.keyboardNavigation) break;
14804 dir = e.keyCode == 37 ? -1 : 1;
14807 newDate = this.moveYear(this.date, dir);
14808 newViewDate = this.moveYear(this.viewDate, dir);
14809 } else if (e.shiftKey){
14810 newDate = this.moveMonth(this.date, dir);
14811 newViewDate = this.moveMonth(this.viewDate, dir);
14813 newDate = new Date(this.date);
14814 newDate.setUTCDate(this.date.getUTCDate() + dir);
14815 newViewDate = new Date(this.viewDate);
14816 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14818 if (this.dateWithinRange(newDate)){
14819 this.date = newDate;
14820 this.viewDate = newViewDate;
14821 this.setValue(this.formatDate(this.date));
14823 e.preventDefault();
14824 dateChanged = true;
14829 if (!this.keyboardNavigation) break;
14830 dir = e.keyCode == 38 ? -1 : 1;
14832 newDate = this.moveYear(this.date, dir);
14833 newViewDate = this.moveYear(this.viewDate, dir);
14834 } else if (e.shiftKey){
14835 newDate = this.moveMonth(this.date, dir);
14836 newViewDate = this.moveMonth(this.viewDate, dir);
14838 newDate = new Date(this.date);
14839 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14840 newViewDate = new Date(this.viewDate);
14841 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14843 if (this.dateWithinRange(newDate)){
14844 this.date = newDate;
14845 this.viewDate = newViewDate;
14846 this.setValue(this.formatDate(this.date));
14848 e.preventDefault();
14849 dateChanged = true;
14853 this.setValue(this.formatDate(this.date));
14855 e.preventDefault();
14858 this.setValue(this.formatDate(this.date));
14872 onClick: function(e)
14874 e.stopPropagation();
14875 e.preventDefault();
14877 var target = e.getTarget();
14879 if(target.nodeName.toLowerCase() === 'i'){
14880 target = Roo.get(target).dom.parentNode;
14883 var nodeName = target.nodeName;
14884 var className = target.className;
14885 var html = target.innerHTML;
14887 switch(nodeName.toLowerCase()) {
14889 switch(className) {
14895 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14896 switch(this.viewMode){
14898 this.viewDate = this.moveMonth(this.viewDate, dir);
14902 this.viewDate = this.moveYear(this.viewDate, dir);
14908 var date = new Date();
14909 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14911 this.setValue(this.formatDate(this.date));
14918 if (className.indexOf('disabled') === -1) {
14919 this.viewDate.setUTCDate(1);
14920 if (className.indexOf('month') !== -1) {
14921 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14923 var year = parseInt(html, 10) || 0;
14924 this.viewDate.setUTCFullYear(year);
14933 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
14934 var day = parseInt(html, 10) || 1;
14935 var year = this.viewDate.getUTCFullYear(),
14936 month = this.viewDate.getUTCMonth();
14938 if (className.indexOf('old') !== -1) {
14945 } else if (className.indexOf('new') !== -1) {
14953 this.date = this.UTCDate(year, month, day,0,0,0,0);
14954 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
14956 this.setValue(this.formatDate(this.date));
14963 setStartDate: function(startDate)
14965 this.startDate = startDate || -Infinity;
14966 if (this.startDate !== -Infinity) {
14967 this.startDate = this.parseDate(this.startDate);
14970 this.updateNavArrows();
14973 setEndDate: function(endDate)
14975 this.endDate = endDate || Infinity;
14976 if (this.endDate !== Infinity) {
14977 this.endDate = this.parseDate(this.endDate);
14980 this.updateNavArrows();
14983 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
14985 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
14986 if (typeof(this.daysOfWeekDisabled) !== 'object') {
14987 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
14989 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
14990 return parseInt(d, 10);
14993 this.updateNavArrows();
14996 updateNavArrows: function()
14998 var d = new Date(this.viewDate),
14999 year = d.getUTCFullYear(),
15000 month = d.getUTCMonth();
15002 Roo.each(this.picker().select('.prev', true).elements, function(v){
15004 switch (this.viewMode) {
15007 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15013 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15020 Roo.each(this.picker().select('.next', true).elements, function(v){
15022 switch (this.viewMode) {
15025 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15031 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15039 moveMonth: function(date, dir)
15041 if (!dir) return date;
15042 var new_date = new Date(date.valueOf()),
15043 day = new_date.getUTCDate(),
15044 month = new_date.getUTCMonth(),
15045 mag = Math.abs(dir),
15047 dir = dir > 0 ? 1 : -1;
15050 // If going back one month, make sure month is not current month
15051 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15053 return new_date.getUTCMonth() == month;
15055 // If going forward one month, make sure month is as expected
15056 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15058 return new_date.getUTCMonth() != new_month;
15060 new_month = month + dir;
15061 new_date.setUTCMonth(new_month);
15062 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15063 if (new_month < 0 || new_month > 11)
15064 new_month = (new_month + 12) % 12;
15066 // For magnitudes >1, move one month at a time...
15067 for (var i=0; i<mag; i++)
15068 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15069 new_date = this.moveMonth(new_date, dir);
15070 // ...then reset the day, keeping it in the new month
15071 new_month = new_date.getUTCMonth();
15072 new_date.setUTCDate(day);
15074 return new_month != new_date.getUTCMonth();
15077 // Common date-resetting loop -- if date is beyond end of month, make it
15080 new_date.setUTCDate(--day);
15081 new_date.setUTCMonth(new_month);
15086 moveYear: function(date, dir)
15088 return this.moveMonth(date, dir*12);
15091 dateWithinRange: function(date)
15093 return date >= this.startDate && date <= this.endDate;
15099 this.picker().remove();
15104 Roo.apply(Roo.bootstrap.DateField, {
15115 html: '<i class="fa fa-arrow-left"/>'
15125 html: '<i class="fa fa-arrow-right"/>'
15167 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15168 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15169 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15170 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15171 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15184 navFnc: 'FullYear',
15189 navFnc: 'FullYear',
15194 Roo.apply(Roo.bootstrap.DateField, {
15198 cls: 'datepicker dropdown-menu',
15202 cls: 'datepicker-days',
15206 cls: 'table-condensed',
15208 Roo.bootstrap.DateField.head,
15212 Roo.bootstrap.DateField.footer
15219 cls: 'datepicker-months',
15223 cls: 'table-condensed',
15225 Roo.bootstrap.DateField.head,
15226 Roo.bootstrap.DateField.content,
15227 Roo.bootstrap.DateField.footer
15234 cls: 'datepicker-years',
15238 cls: 'table-condensed',
15240 Roo.bootstrap.DateField.head,
15241 Roo.bootstrap.DateField.content,
15242 Roo.bootstrap.DateField.footer
15261 * @class Roo.bootstrap.TimeField
15262 * @extends Roo.bootstrap.Input
15263 * Bootstrap DateField class
15267 * Create a new TimeField
15268 * @param {Object} config The config object
15271 Roo.bootstrap.TimeField = function(config){
15272 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15276 * Fires when this field show.
15277 * @param {Roo.bootstrap.DateField} this
15278 * @param {Mixed} date The date value
15283 * Fires when this field hide.
15284 * @param {Roo.bootstrap.DateField} this
15285 * @param {Mixed} date The date value
15290 * Fires when select a date.
15291 * @param {Roo.bootstrap.DateField} this
15292 * @param {Mixed} date The date value
15298 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
15301 * @cfg {String} format
15302 * The default time format string which can be overriden for localization support. The format must be
15303 * valid according to {@link Date#parseDate} (defaults to 'H:i').
15307 onRender: function(ct, position)
15310 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15312 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15314 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15316 this.pop = this.picker().select('>.datepicker-time',true).first();
15317 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
15319 this.picker().on('mousedown', this.onMousedown, this);
15320 this.picker().on('click', this.onClick, this);
15322 this.picker().addClass('datepicker-dropdown');
15327 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15328 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15329 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15330 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15331 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15332 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15336 fireKey: function(e){
15337 if (!this.picker().isVisible()){
15338 if (e.keyCode == 27) // allow escape to hide and re-show picker
15343 e.preventDefault();
15351 this.onTogglePeriod();
15354 this.onIncrementMinutes();
15357 this.onDecrementMinutes();
15366 onClick: function(e) {
15367 e.stopPropagation();
15368 e.preventDefault();
15371 picker : function()
15373 return this.el.select('.datepicker', true).first();
15376 fillTime: function()
15378 var time = this.pop.select('tbody', true).first();
15380 time.dom.innerHTML = '';
15395 cls: 'hours-up glyphicon glyphicon-chevron-up'
15415 cls: 'minutes-up glyphicon glyphicon-chevron-up'
15436 cls: 'timepicker-hour',
15451 cls: 'timepicker-minute',
15466 cls: 'btn btn-primary period',
15488 cls: 'hours-down glyphicon glyphicon-chevron-down'
15508 cls: 'minutes-down glyphicon glyphicon-chevron-down'
15526 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15533 var hours = this.time.getHours();
15534 var minutes = this.time.getMinutes();
15547 hours = hours - 12;
15551 hours = '0' + hours;
15555 minutes = '0' + minutes;
15558 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15559 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15560 this.pop.select('button', true).first().dom.innerHTML = period;
15566 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15568 var cls = ['bottom'];
15570 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15577 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15582 this.picker().addClass(cls.join('-'));
15586 Roo.each(cls, function(c){
15588 _this.picker().setTop(_this.inputEl().getHeight());
15592 _this.picker().setTop(0 - _this.picker().getHeight());
15597 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15601 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15608 onFocus : function()
15610 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15614 onBlur : function()
15616 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15622 this.picker().show();
15627 this.fireEvent('show', this, this.date);
15632 this.picker().hide();
15635 this.fireEvent('hide', this, this.date);
15638 setTime : function()
15641 this.setValue(this.time.format(this.format));
15643 this.fireEvent('select', this, this.date);
15648 onMousedown: function(e){
15649 e.stopPropagation();
15650 e.preventDefault();
15653 onIncrementHours: function()
15655 Roo.log('onIncrementHours');
15656 this.time = this.time.add(Date.HOUR, 1);
15661 onDecrementHours: function()
15663 Roo.log('onDecrementHours');
15664 this.time = this.time.add(Date.HOUR, -1);
15668 onIncrementMinutes: function()
15670 Roo.log('onIncrementMinutes');
15671 this.time = this.time.add(Date.MINUTE, 1);
15675 onDecrementMinutes: function()
15677 Roo.log('onDecrementMinutes');
15678 this.time = this.time.add(Date.MINUTE, -1);
15682 onTogglePeriod: function()
15684 Roo.log('onTogglePeriod');
15685 this.time = this.time.add(Date.HOUR, 12);
15692 Roo.apply(Roo.bootstrap.TimeField, {
15722 cls: 'btn btn-info ok',
15734 Roo.apply(Roo.bootstrap.TimeField, {
15738 cls: 'datepicker dropdown-menu',
15742 cls: 'datepicker-time',
15746 cls: 'table-condensed',
15748 Roo.bootstrap.TimeField.content,
15749 Roo.bootstrap.TimeField.footer
15768 * @class Roo.bootstrap.CheckBox
15769 * @extends Roo.bootstrap.Input
15770 * Bootstrap CheckBox class
15772 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15773 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15774 * @cfg {String} boxLabel The text that appears beside the checkbox
15775 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15776 * @cfg {Boolean} checked initnal the element
15780 * Create a new CheckBox
15781 * @param {Object} config The config object
15784 Roo.bootstrap.CheckBox = function(config){
15785 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15790 * Fires when the element is checked or unchecked.
15791 * @param {Roo.bootstrap.CheckBox} this This input
15792 * @param {Boolean} checked The new checked value
15798 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
15800 inputType: 'checkbox',
15807 getAutoCreate : function()
15809 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15815 cfg.cls = 'form-group checkbox' //input-group
15823 type : this.inputType,
15824 value : (!this.checked) ? this.valueOff : this.inputValue,
15825 cls : 'roo-checkbox', //'form-box',
15826 placeholder : this.placeholder || ''
15830 if (this.weight) { // Validity check?
15831 cfg.cls += " checkbox-" + this.weight;
15834 if (this.disabled) {
15835 input.disabled=true;
15839 input.checked = this.checked;
15843 input.name = this.name;
15847 input.cls += ' input-' + this.size;
15851 ['xs','sm','md','lg'].map(function(size){
15852 if (settings[size]) {
15853 cfg.cls += ' col-' + size + '-' + settings[size];
15859 var inputblock = input;
15864 if (this.before || this.after) {
15867 cls : 'input-group',
15871 inputblock.cn.push({
15873 cls : 'input-group-addon',
15877 inputblock.cn.push(input);
15879 inputblock.cn.push({
15881 cls : 'input-group-addon',
15888 if (align ==='left' && this.fieldLabel.length) {
15889 Roo.log("left and has label");
15895 cls : 'control-label col-md-' + this.labelWidth,
15896 html : this.fieldLabel
15900 cls : "col-md-" + (12 - this.labelWidth),
15907 } else if ( this.fieldLabel.length) {
15912 tag: this.boxLabel ? 'span' : 'label',
15914 cls: 'control-label box-input-label',
15915 //cls : 'input-group-addon',
15916 html : this.fieldLabel
15926 Roo.log(" no label && no align");
15927 cfg.cn = [ inputblock ] ;
15936 html: this.boxLabel
15948 * return the real input element.
15950 inputEl: function ()
15952 return this.el.select('input.roo-checkbox',true).first();
15957 return this.el.select('label.control-label',true).first();
15960 initEvents : function()
15962 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
15964 this.inputEl().on('click', this.onClick, this);
15968 onClick : function()
15970 this.setChecked(!this.checked);
15973 setChecked : function(state,suppressEvent)
15975 this.checked = state;
15977 this.inputEl().dom.checked = state;
15979 if(suppressEvent !== true){
15980 this.fireEvent('check', this, state);
15983 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15987 setValue : function(v,suppressEvent)
15989 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
16003 * @class Roo.bootstrap.Radio
16004 * @extends Roo.bootstrap.CheckBox
16005 * Bootstrap Radio class
16008 * Create a new Radio
16009 * @param {Object} config The config object
16012 Roo.bootstrap.Radio = function(config){
16013 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
16017 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
16019 inputType: 'radio',
16023 getAutoCreate : function()
16025 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16031 cfg.cls = 'form-group radio' //input-group
16036 type : this.inputType,
16037 value : (!this.checked) ? this.valueOff : this.inputValue,
16039 placeholder : this.placeholder || ''
16042 if (this.weight) { // Validity check?
16043 cfg.cls += " radio-" + this.weight;
16045 if (this.disabled) {
16046 input.disabled=true;
16050 input.checked = this.checked;
16054 input.name = this.name;
16058 input.cls += ' input-' + this.size;
16062 ['xs','sm','md','lg'].map(function(size){
16063 if (settings[size]) {
16064 cfg.cls += ' col-' + size + '-' + settings[size];
16068 var inputblock = input;
16070 if (this.before || this.after) {
16073 cls : 'input-group',
16077 inputblock.cn.push({
16079 cls : 'input-group-addon',
16083 inputblock.cn.push(input);
16085 inputblock.cn.push({
16087 cls : 'input-group-addon',
16094 if (align ==='left' && this.fieldLabel.length) {
16095 Roo.log("left and has label");
16101 cls : 'control-label col-md-' + this.labelWidth,
16102 html : this.fieldLabel
16106 cls : "col-md-" + (12 - this.labelWidth),
16113 } else if ( this.fieldLabel.length) {
16120 cls: 'control-label box-input-label',
16121 //cls : 'input-group-addon',
16122 html : this.fieldLabel
16132 Roo.log(" no label && no align");
16147 html: this.boxLabel
16154 inputEl: function ()
16156 return this.el.select('input.roo-radio',true).first();
16158 onClick : function()
16160 this.setChecked(true);
16163 setChecked : function(state,suppressEvent)
16166 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16167 v.dom.checked = false;
16171 this.checked = state;
16172 this.inputEl().dom.checked = state;
16174 if(suppressEvent !== true){
16175 this.fireEvent('check', this, state);
16178 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16182 getGroupValue : function()
16185 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16186 if(v.dom.checked == true){
16187 value = v.dom.value;
16195 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
16196 * @return {Mixed} value The field value
16198 getValue : function(){
16199 return this.getGroupValue();
16205 //<script type="text/javascript">
16208 * Based Ext JS Library 1.1.1
16209 * Copyright(c) 2006-2007, Ext JS, LLC.
16215 * @class Roo.HtmlEditorCore
16216 * @extends Roo.Component
16217 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16219 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16222 Roo.HtmlEditorCore = function(config){
16225 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16228 * @event initialize
16229 * Fires when the editor is fully initialized (including the iframe)
16230 * @param {Roo.HtmlEditorCore} this
16235 * Fires when the editor is first receives the focus. Any insertion must wait
16236 * until after this event.
16237 * @param {Roo.HtmlEditorCore} this
16241 * @event beforesync
16242 * Fires before the textarea is updated with content from the editor iframe. Return false
16243 * to cancel the sync.
16244 * @param {Roo.HtmlEditorCore} this
16245 * @param {String} html
16249 * @event beforepush
16250 * Fires before the iframe editor is updated with content from the textarea. Return false
16251 * to cancel the push.
16252 * @param {Roo.HtmlEditorCore} this
16253 * @param {String} html
16258 * Fires when the textarea is updated with content from the editor iframe.
16259 * @param {Roo.HtmlEditorCore} this
16260 * @param {String} html
16265 * Fires when the iframe editor is updated with content from the textarea.
16266 * @param {Roo.HtmlEditorCore} this
16267 * @param {String} html
16272 * @event editorevent
16273 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16274 * @param {Roo.HtmlEditorCore} this
16282 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
16286 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
16292 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16297 * @cfg {Number} height (in pixels)
16301 * @cfg {Number} width (in pixels)
16306 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16309 stylesheets: false,
16314 // private properties
16315 validationEvent : false,
16317 initialized : false,
16319 sourceEditMode : false,
16320 onFocus : Roo.emptyFn,
16322 hideMode:'offsets',
16330 * Protected method that will not generally be called directly. It
16331 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16332 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16334 getDocMarkup : function(){
16337 Roo.log(this.stylesheets);
16339 // inherit styels from page...??
16340 if (this.stylesheets === false) {
16342 Roo.get(document.head).select('style').each(function(node) {
16343 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16346 Roo.get(document.head).select('link').each(function(node) {
16347 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16350 } else if (!this.stylesheets.length) {
16352 st = '<style type="text/css">' +
16353 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16356 Roo.each(this.stylesheets, function(s) {
16357 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16362 st += '<style type="text/css">' +
16363 'IMG { cursor: pointer } ' +
16367 return '<html><head>' + st +
16368 //<style type="text/css">' +
16369 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16371 ' </head><body class="roo-htmleditor-body"></body></html>';
16375 onRender : function(ct, position)
16378 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16379 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16382 this.el.dom.style.border = '0 none';
16383 this.el.dom.setAttribute('tabIndex', -1);
16384 this.el.addClass('x-hidden hide');
16388 if(Roo.isIE){ // fix IE 1px bogus margin
16389 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16393 this.frameId = Roo.id();
16397 var iframe = this.owner.wrap.createChild({
16399 cls: 'form-control', // bootstrap..
16401 name: this.frameId,
16402 frameBorder : 'no',
16403 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16408 this.iframe = iframe.dom;
16410 this.assignDocWin();
16412 this.doc.designMode = 'on';
16415 this.doc.write(this.getDocMarkup());
16419 var task = { // must defer to wait for browser to be ready
16421 //console.log("run task?" + this.doc.readyState);
16422 this.assignDocWin();
16423 if(this.doc.body || this.doc.readyState == 'complete'){
16425 this.doc.designMode="on";
16429 Roo.TaskMgr.stop(task);
16430 this.initEditor.defer(10, this);
16437 Roo.TaskMgr.start(task);
16444 onResize : function(w, h)
16446 Roo.log('resize: ' +w + ',' + h );
16447 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16451 if(typeof w == 'number'){
16453 this.iframe.style.width = w + 'px';
16455 if(typeof h == 'number'){
16457 this.iframe.style.height = h + 'px';
16459 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16466 * Toggles the editor between standard and source edit mode.
16467 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16469 toggleSourceEdit : function(sourceEditMode){
16471 this.sourceEditMode = sourceEditMode === true;
16473 if(this.sourceEditMode){
16475 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
16478 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16479 //this.iframe.className = '';
16482 //this.setSize(this.owner.wrap.getSize());
16483 //this.fireEvent('editmodechange', this, this.sourceEditMode);
16490 * Protected method that will not generally be called directly. If you need/want
16491 * custom HTML cleanup, this is the method you should override.
16492 * @param {String} html The HTML to be cleaned
16493 * return {String} The cleaned HTML
16495 cleanHtml : function(html){
16496 html = String(html);
16497 if(html.length > 5){
16498 if(Roo.isSafari){ // strip safari nonsense
16499 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16502 if(html == ' '){
16509 * HTML Editor -> Textarea
16510 * Protected method that will not generally be called directly. Syncs the contents
16511 * of the editor iframe with the textarea.
16513 syncValue : function(){
16514 if(this.initialized){
16515 var bd = (this.doc.body || this.doc.documentElement);
16516 //this.cleanUpPaste(); -- this is done else where and causes havoc..
16517 var html = bd.innerHTML;
16519 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16520 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16522 html = '<div style="'+m[0]+'">' + html + '</div>';
16525 html = this.cleanHtml(html);
16526 // fix up the special chars.. normaly like back quotes in word...
16527 // however we do not want to do this with chinese..
16528 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16529 var cc = b.charCodeAt();
16531 (cc >= 0x4E00 && cc < 0xA000 ) ||
16532 (cc >= 0x3400 && cc < 0x4E00 ) ||
16533 (cc >= 0xf900 && cc < 0xfb00 )
16539 if(this.owner.fireEvent('beforesync', this, html) !== false){
16540 this.el.dom.value = html;
16541 this.owner.fireEvent('sync', this, html);
16547 * Protected method that will not generally be called directly. Pushes the value of the textarea
16548 * into the iframe editor.
16550 pushValue : function(){
16551 if(this.initialized){
16552 var v = this.el.dom.value.trim();
16554 // if(v.length < 1){
16558 if(this.owner.fireEvent('beforepush', this, v) !== false){
16559 var d = (this.doc.body || this.doc.documentElement);
16561 this.cleanUpPaste();
16562 this.el.dom.value = d.innerHTML;
16563 this.owner.fireEvent('push', this, v);
16569 deferFocus : function(){
16570 this.focus.defer(10, this);
16574 focus : function(){
16575 if(this.win && !this.sourceEditMode){
16582 assignDocWin: function()
16584 var iframe = this.iframe;
16587 this.doc = iframe.contentWindow.document;
16588 this.win = iframe.contentWindow;
16590 // if (!Roo.get(this.frameId)) {
16593 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16594 // this.win = Roo.get(this.frameId).dom.contentWindow;
16596 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
16600 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16601 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
16606 initEditor : function(){
16607 //console.log("INIT EDITOR");
16608 this.assignDocWin();
16612 this.doc.designMode="on";
16614 this.doc.write(this.getDocMarkup());
16617 var dbody = (this.doc.body || this.doc.documentElement);
16618 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16619 // this copies styles from the containing element into thsi one..
16620 // not sure why we need all of this..
16621 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16623 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16624 //ss['background-attachment'] = 'fixed'; // w3c
16625 dbody.bgProperties = 'fixed'; // ie
16626 //Roo.DomHelper.applyStyles(dbody, ss);
16627 Roo.EventManager.on(this.doc, {
16628 //'mousedown': this.onEditorEvent,
16629 'mouseup': this.onEditorEvent,
16630 'dblclick': this.onEditorEvent,
16631 'click': this.onEditorEvent,
16632 'keyup': this.onEditorEvent,
16637 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16639 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16640 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16642 this.initialized = true;
16644 this.owner.fireEvent('initialize', this);
16649 onDestroy : function(){
16655 //for (var i =0; i < this.toolbars.length;i++) {
16656 // // fixme - ask toolbars for heights?
16657 // this.toolbars[i].onDestroy();
16660 //this.wrap.dom.innerHTML = '';
16661 //this.wrap.remove();
16666 onFirstFocus : function(){
16668 this.assignDocWin();
16671 this.activated = true;
16674 if(Roo.isGecko){ // prevent silly gecko errors
16676 var s = this.win.getSelection();
16677 if(!s.focusNode || s.focusNode.nodeType != 3){
16678 var r = s.getRangeAt(0);
16679 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16684 this.execCmd('useCSS', true);
16685 this.execCmd('styleWithCSS', false);
16688 this.owner.fireEvent('activate', this);
16692 adjustFont: function(btn){
16693 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16694 //if(Roo.isSafari){ // safari
16697 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16698 if(Roo.isSafari){ // safari
16699 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16700 v = (v < 10) ? 10 : v;
16701 v = (v > 48) ? 48 : v;
16702 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16707 v = Math.max(1, v+adjust);
16709 this.execCmd('FontSize', v );
16712 onEditorEvent : function(e){
16713 this.owner.fireEvent('editorevent', this, e);
16714 // this.updateToolbar();
16715 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16718 insertTag : function(tg)
16720 // could be a bit smarter... -> wrap the current selected tRoo..
16721 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16723 range = this.createRange(this.getSelection());
16724 var wrappingNode = this.doc.createElement(tg.toLowerCase());
16725 wrappingNode.appendChild(range.extractContents());
16726 range.insertNode(wrappingNode);
16733 this.execCmd("formatblock", tg);
16737 insertText : function(txt)
16741 var range = this.createRange();
16742 range.deleteContents();
16743 //alert(Sender.getAttribute('label'));
16745 range.insertNode(this.doc.createTextNode(txt));
16751 * Executes a Midas editor command on the editor document and performs necessary focus and
16752 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16753 * @param {String} cmd The Midas command
16754 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16756 relayCmd : function(cmd, value){
16758 this.execCmd(cmd, value);
16759 this.owner.fireEvent('editorevent', this);
16760 //this.updateToolbar();
16761 this.owner.deferFocus();
16765 * Executes a Midas editor command directly on the editor document.
16766 * For visual commands, you should use {@link #relayCmd} instead.
16767 * <b>This should only be called after the editor is initialized.</b>
16768 * @param {String} cmd The Midas command
16769 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16771 execCmd : function(cmd, value){
16772 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16779 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16781 * @param {String} text | dom node..
16783 insertAtCursor : function(text)
16788 if(!this.activated){
16794 var r = this.doc.selection.createRange();
16805 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16809 // from jquery ui (MIT licenced)
16811 var win = this.win;
16813 if (win.getSelection && win.getSelection().getRangeAt) {
16814 range = win.getSelection().getRangeAt(0);
16815 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16816 range.insertNode(node);
16817 } else if (win.document.selection && win.document.selection.createRange) {
16818 // no firefox support
16819 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16820 win.document.selection.createRange().pasteHTML(txt);
16822 // no firefox support
16823 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16824 this.execCmd('InsertHTML', txt);
16833 mozKeyPress : function(e){
16835 var c = e.getCharCode(), cmd;
16838 c = String.fromCharCode(c).toLowerCase();
16852 this.cleanUpPaste.defer(100, this);
16860 e.preventDefault();
16868 fixKeys : function(){ // load time branching for fastest keydown performance
16870 return function(e){
16871 var k = e.getKey(), r;
16874 r = this.doc.selection.createRange();
16877 r.pasteHTML('    ');
16884 r = this.doc.selection.createRange();
16886 var target = r.parentElement();
16887 if(!target || target.tagName.toLowerCase() != 'li'){
16889 r.pasteHTML('<br />');
16895 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16896 this.cleanUpPaste.defer(100, this);
16902 }else if(Roo.isOpera){
16903 return function(e){
16904 var k = e.getKey();
16908 this.execCmd('InsertHTML','    ');
16911 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16912 this.cleanUpPaste.defer(100, this);
16917 }else if(Roo.isSafari){
16918 return function(e){
16919 var k = e.getKey();
16923 this.execCmd('InsertText','\t');
16927 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16928 this.cleanUpPaste.defer(100, this);
16936 getAllAncestors: function()
16938 var p = this.getSelectedNode();
16941 a.push(p); // push blank onto stack..
16942 p = this.getParentElement();
16946 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
16950 a.push(this.doc.body);
16954 lastSelNode : false,
16957 getSelection : function()
16959 this.assignDocWin();
16960 return Roo.isIE ? this.doc.selection : this.win.getSelection();
16963 getSelectedNode: function()
16965 // this may only work on Gecko!!!
16967 // should we cache this!!!!
16972 var range = this.createRange(this.getSelection()).cloneRange();
16975 var parent = range.parentElement();
16977 var testRange = range.duplicate();
16978 testRange.moveToElementText(parent);
16979 if (testRange.inRange(range)) {
16982 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
16985 parent = parent.parentElement;
16990 // is ancestor a text element.
16991 var ac = range.commonAncestorContainer;
16992 if (ac.nodeType == 3) {
16993 ac = ac.parentNode;
16996 var ar = ac.childNodes;
16999 var other_nodes = [];
17000 var has_other_nodes = false;
17001 for (var i=0;i<ar.length;i++) {
17002 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
17005 // fullly contained node.
17007 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
17012 // probably selected..
17013 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
17014 other_nodes.push(ar[i]);
17018 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
17023 has_other_nodes = true;
17025 if (!nodes.length && other_nodes.length) {
17026 nodes= other_nodes;
17028 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
17034 createRange: function(sel)
17036 // this has strange effects when using with
17037 // top toolbar - not sure if it's a great idea.
17038 //this.editor.contentWindow.focus();
17039 if (typeof sel != "undefined") {
17041 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
17043 return this.doc.createRange();
17046 return this.doc.createRange();
17049 getParentElement: function()
17052 this.assignDocWin();
17053 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
17055 var range = this.createRange(sel);
17058 var p = range.commonAncestorContainer;
17059 while (p.nodeType == 3) { // text node
17070 * Range intersection.. the hard stuff...
17074 * [ -- selected range --- ]
17078 * if end is before start or hits it. fail.
17079 * if start is after end or hits it fail.
17081 * if either hits (but other is outside. - then it's not
17087 // @see http://www.thismuchiknow.co.uk/?p=64.
17088 rangeIntersectsNode : function(range, node)
17090 var nodeRange = node.ownerDocument.createRange();
17092 nodeRange.selectNode(node);
17094 nodeRange.selectNodeContents(node);
17097 var rangeStartRange = range.cloneRange();
17098 rangeStartRange.collapse(true);
17100 var rangeEndRange = range.cloneRange();
17101 rangeEndRange.collapse(false);
17103 var nodeStartRange = nodeRange.cloneRange();
17104 nodeStartRange.collapse(true);
17106 var nodeEndRange = nodeRange.cloneRange();
17107 nodeEndRange.collapse(false);
17109 return rangeStartRange.compareBoundaryPoints(
17110 Range.START_TO_START, nodeEndRange) == -1 &&
17111 rangeEndRange.compareBoundaryPoints(
17112 Range.START_TO_START, nodeStartRange) == 1;
17116 rangeCompareNode : function(range, node)
17118 var nodeRange = node.ownerDocument.createRange();
17120 nodeRange.selectNode(node);
17122 nodeRange.selectNodeContents(node);
17126 range.collapse(true);
17128 nodeRange.collapse(true);
17130 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17131 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
17133 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17135 var nodeIsBefore = ss == 1;
17136 var nodeIsAfter = ee == -1;
17138 if (nodeIsBefore && nodeIsAfter)
17140 if (!nodeIsBefore && nodeIsAfter)
17141 return 1; //right trailed.
17143 if (nodeIsBefore && !nodeIsAfter)
17144 return 2; // left trailed.
17149 // private? - in a new class?
17150 cleanUpPaste : function()
17152 // cleans up the whole document..
17153 Roo.log('cleanuppaste');
17155 this.cleanUpChildren(this.doc.body);
17156 var clean = this.cleanWordChars(this.doc.body.innerHTML);
17157 if (clean != this.doc.body.innerHTML) {
17158 this.doc.body.innerHTML = clean;
17163 cleanWordChars : function(input) {// change the chars to hex code
17164 var he = Roo.HtmlEditorCore;
17166 var output = input;
17167 Roo.each(he.swapCodes, function(sw) {
17168 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17170 output = output.replace(swapper, sw[1]);
17177 cleanUpChildren : function (n)
17179 if (!n.childNodes.length) {
17182 for (var i = n.childNodes.length-1; i > -1 ; i--) {
17183 this.cleanUpChild(n.childNodes[i]);
17190 cleanUpChild : function (node)
17193 //console.log(node);
17194 if (node.nodeName == "#text") {
17195 // clean up silly Windows -- stuff?
17198 if (node.nodeName == "#comment") {
17199 node.parentNode.removeChild(node);
17200 // clean up silly Windows -- stuff?
17204 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
17206 node.parentNode.removeChild(node);
17211 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17213 // remove <a name=....> as rendering on yahoo mailer is borked with this.
17214 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17216 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17217 // remove_keep_children = true;
17220 if (remove_keep_children) {
17221 this.cleanUpChildren(node);
17222 // inserts everything just before this node...
17223 while (node.childNodes.length) {
17224 var cn = node.childNodes[0];
17225 node.removeChild(cn);
17226 node.parentNode.insertBefore(cn, node);
17228 node.parentNode.removeChild(node);
17232 if (!node.attributes || !node.attributes.length) {
17233 this.cleanUpChildren(node);
17237 function cleanAttr(n,v)
17240 if (v.match(/^\./) || v.match(/^\//)) {
17243 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17246 if (v.match(/^#/)) {
17249 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17250 node.removeAttribute(n);
17254 function cleanStyle(n,v)
17256 if (v.match(/expression/)) { //XSS?? should we even bother..
17257 node.removeAttribute(n);
17260 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
17261 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
17264 var parts = v.split(/;/);
17267 Roo.each(parts, function(p) {
17268 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17272 var l = p.split(':').shift().replace(/\s+/g,'');
17273 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17275 if ( cblack.indexOf(l) > -1) {
17276 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17277 //node.removeAttribute(n);
17281 // only allow 'c whitelisted system attributes'
17282 if ( cwhite.length && cwhite.indexOf(l) < 0) {
17283 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17284 //node.removeAttribute(n);
17294 if (clean.length) {
17295 node.setAttribute(n, clean.join(';'));
17297 node.removeAttribute(n);
17303 for (var i = node.attributes.length-1; i > -1 ; i--) {
17304 var a = node.attributes[i];
17307 if (a.name.toLowerCase().substr(0,2)=='on') {
17308 node.removeAttribute(a.name);
17311 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17312 node.removeAttribute(a.name);
17315 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17316 cleanAttr(a.name,a.value); // fixme..
17319 if (a.name == 'style') {
17320 cleanStyle(a.name,a.value);
17323 /// clean up MS crap..
17324 // tecnically this should be a list of valid class'es..
17327 if (a.name == 'class') {
17328 if (a.value.match(/^Mso/)) {
17329 node.className = '';
17332 if (a.value.match(/body/)) {
17333 node.className = '';
17344 this.cleanUpChildren(node);
17349 * Clean up MS wordisms...
17351 cleanWord : function(node)
17354 var cleanWordChildren = function()
17356 if (!node.childNodes.length) {
17359 for (var i = node.childNodes.length-1; i > -1 ; i--) {
17360 _t.cleanWord(node.childNodes[i]);
17366 this.cleanWord(this.doc.body);
17369 if (node.nodeName == "#text") {
17370 // clean up silly Windows -- stuff?
17373 if (node.nodeName == "#comment") {
17374 node.parentNode.removeChild(node);
17375 // clean up silly Windows -- stuff?
17379 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17380 node.parentNode.removeChild(node);
17384 // remove - but keep children..
17385 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17386 while (node.childNodes.length) {
17387 var cn = node.childNodes[0];
17388 node.removeChild(cn);
17389 node.parentNode.insertBefore(cn, node);
17391 node.parentNode.removeChild(node);
17392 cleanWordChildren();
17396 if (node.className.length) {
17398 var cn = node.className.split(/\W+/);
17400 Roo.each(cn, function(cls) {
17401 if (cls.match(/Mso[a-zA-Z]+/)) {
17406 node.className = cna.length ? cna.join(' ') : '';
17408 node.removeAttribute("class");
17412 if (node.hasAttribute("lang")) {
17413 node.removeAttribute("lang");
17416 if (node.hasAttribute("style")) {
17418 var styles = node.getAttribute("style").split(";");
17420 Roo.each(styles, function(s) {
17421 if (!s.match(/:/)) {
17424 var kv = s.split(":");
17425 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17428 // what ever is left... we allow.
17431 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17432 if (!nstyle.length) {
17433 node.removeAttribute('style');
17437 cleanWordChildren();
17441 domToHTML : function(currentElement, depth, nopadtext) {
17443 depth = depth || 0;
17444 nopadtext = nopadtext || false;
17446 if (!currentElement) {
17447 return this.domToHTML(this.doc.body);
17450 //Roo.log(currentElement);
17452 var allText = false;
17453 var nodeName = currentElement.nodeName;
17454 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17456 if (nodeName == '#text') {
17457 return currentElement.nodeValue;
17462 if (nodeName != 'BODY') {
17465 // Prints the node tagName, such as <A>, <IMG>, etc
17468 for(i = 0; i < currentElement.attributes.length;i++) {
17470 var aname = currentElement.attributes.item(i).name;
17471 if (!currentElement.attributes.item(i).value.length) {
17474 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17477 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17486 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17489 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17494 // Traverse the tree
17496 var currentElementChild = currentElement.childNodes.item(i);
17497 var allText = true;
17498 var innerHTML = '';
17500 while (currentElementChild) {
17501 // Formatting code (indent the tree so it looks nice on the screen)
17502 var nopad = nopadtext;
17503 if (lastnode == 'SPAN') {
17507 if (currentElementChild.nodeName == '#text') {
17508 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17509 if (!nopad && toadd.length > 80) {
17510 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
17512 innerHTML += toadd;
17515 currentElementChild = currentElement.childNodes.item(i);
17521 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
17523 // Recursively traverse the tree structure of the child node
17524 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
17525 lastnode = currentElementChild.nodeName;
17527 currentElementChild=currentElement.childNodes.item(i);
17533 // The remaining code is mostly for formatting the tree
17534 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
17539 ret+= "</"+tagName+">";
17545 // hide stuff that is not compatible
17559 * @event specialkey
17563 * @cfg {String} fieldClass @hide
17566 * @cfg {String} focusClass @hide
17569 * @cfg {String} autoCreate @hide
17572 * @cfg {String} inputType @hide
17575 * @cfg {String} invalidClass @hide
17578 * @cfg {String} invalidText @hide
17581 * @cfg {String} msgFx @hide
17584 * @cfg {String} validateOnBlur @hide
17588 Roo.HtmlEditorCore.white = [
17589 'area', 'br', 'img', 'input', 'hr', 'wbr',
17591 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
17592 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
17593 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
17594 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
17595 'table', 'ul', 'xmp',
17597 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
17600 'dir', 'menu', 'ol', 'ul', 'dl',
17606 Roo.HtmlEditorCore.black = [
17607 // 'embed', 'object', // enable - backend responsiblity to clean thiese
17609 'base', 'basefont', 'bgsound', 'blink', 'body',
17610 'frame', 'frameset', 'head', 'html', 'ilayer',
17611 'iframe', 'layer', 'link', 'meta', 'object',
17612 'script', 'style' ,'title', 'xml' // clean later..
17614 Roo.HtmlEditorCore.clean = [
17615 'script', 'style', 'title', 'xml'
17617 Roo.HtmlEditorCore.remove = [
17622 Roo.HtmlEditorCore.ablack = [
17626 Roo.HtmlEditorCore.aclean = [
17627 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
17631 Roo.HtmlEditorCore.pwhite= [
17632 'http', 'https', 'mailto'
17635 // white listed style attributes.
17636 Roo.HtmlEditorCore.cwhite= [
17637 // 'text-align', /// default is to allow most things..
17643 // black listed style attributes.
17644 Roo.HtmlEditorCore.cblack= [
17645 // 'font-size' -- this can be set by the project
17649 Roo.HtmlEditorCore.swapCodes =[
17668 * @class Roo.bootstrap.HtmlEditor
17669 * @extends Roo.bootstrap.TextArea
17670 * Bootstrap HtmlEditor class
17673 * Create a new HtmlEditor
17674 * @param {Object} config The config object
17677 Roo.bootstrap.HtmlEditor = function(config){
17678 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17679 if (!this.toolbars) {
17680 this.toolbars = [];
17682 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17685 * @event initialize
17686 * Fires when the editor is fully initialized (including the iframe)
17687 * @param {HtmlEditor} this
17692 * Fires when the editor is first receives the focus. Any insertion must wait
17693 * until after this event.
17694 * @param {HtmlEditor} this
17698 * @event beforesync
17699 * Fires before the textarea is updated with content from the editor iframe. Return false
17700 * to cancel the sync.
17701 * @param {HtmlEditor} this
17702 * @param {String} html
17706 * @event beforepush
17707 * Fires before the iframe editor is updated with content from the textarea. Return false
17708 * to cancel the push.
17709 * @param {HtmlEditor} this
17710 * @param {String} html
17715 * Fires when the textarea is updated with content from the editor iframe.
17716 * @param {HtmlEditor} this
17717 * @param {String} html
17722 * Fires when the iframe editor is updated with content from the textarea.
17723 * @param {HtmlEditor} this
17724 * @param {String} html
17728 * @event editmodechange
17729 * Fires when the editor switches edit modes
17730 * @param {HtmlEditor} this
17731 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17733 editmodechange: true,
17735 * @event editorevent
17736 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17737 * @param {HtmlEditor} this
17741 * @event firstfocus
17742 * Fires when on first focus - needed by toolbars..
17743 * @param {HtmlEditor} this
17748 * Auto save the htmlEditor value as a file into Events
17749 * @param {HtmlEditor} this
17753 * @event savedpreview
17754 * preview the saved version of htmlEditor
17755 * @param {HtmlEditor} this
17762 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
17766 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17771 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
17776 * @cfg {Number} height (in pixels)
17780 * @cfg {Number} width (in pixels)
17785 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17788 stylesheets: false,
17793 // private properties
17794 validationEvent : false,
17796 initialized : false,
17799 onFocus : Roo.emptyFn,
17801 hideMode:'offsets',
17804 tbContainer : false,
17806 toolbarContainer :function() {
17807 return this.wrap.select('.x-html-editor-tb',true).first();
17811 * Protected method that will not generally be called directly. It
17812 * is called when the editor creates its toolbar. Override this method if you need to
17813 * add custom toolbar buttons.
17814 * @param {HtmlEditor} editor
17816 createToolbar : function(){
17818 Roo.log("create toolbars");
17820 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17821 this.toolbars[0].render(this.toolbarContainer());
17825 // if (!editor.toolbars || !editor.toolbars.length) {
17826 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17829 // for (var i =0 ; i < editor.toolbars.length;i++) {
17830 // editor.toolbars[i] = Roo.factory(
17831 // typeof(editor.toolbars[i]) == 'string' ?
17832 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
17833 // Roo.bootstrap.HtmlEditor);
17834 // editor.toolbars[i].init(editor);
17840 onRender : function(ct, position)
17842 // Roo.log("Call onRender: " + this.xtype);
17844 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17846 this.wrap = this.inputEl().wrap({
17847 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17850 this.editorcore.onRender(ct, position);
17852 if (this.resizable) {
17853 this.resizeEl = new Roo.Resizable(this.wrap, {
17857 minHeight : this.height,
17858 height: this.height,
17859 handles : this.resizable,
17862 resize : function(r, w, h) {
17863 _t.onResize(w,h); // -something
17869 this.createToolbar(this);
17872 if(!this.width && this.resizable){
17873 this.setSize(this.wrap.getSize());
17875 if (this.resizeEl) {
17876 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17877 // should trigger onReize..
17883 onResize : function(w, h)
17885 Roo.log('resize: ' +w + ',' + h );
17886 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17890 if(this.inputEl() ){
17891 if(typeof w == 'number'){
17892 var aw = w - this.wrap.getFrameWidth('lr');
17893 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17896 if(typeof h == 'number'){
17897 var tbh = -11; // fixme it needs to tool bar size!
17898 for (var i =0; i < this.toolbars.length;i++) {
17899 // fixme - ask toolbars for heights?
17900 tbh += this.toolbars[i].el.getHeight();
17901 //if (this.toolbars[i].footer) {
17902 // tbh += this.toolbars[i].footer.el.getHeight();
17910 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17911 ah -= 5; // knock a few pixes off for look..
17912 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17916 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17917 this.editorcore.onResize(ew,eh);
17922 * Toggles the editor between standard and source edit mode.
17923 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17925 toggleSourceEdit : function(sourceEditMode)
17927 this.editorcore.toggleSourceEdit(sourceEditMode);
17929 if(this.editorcore.sourceEditMode){
17930 Roo.log('editor - showing textarea');
17933 // Roo.log(this.syncValue());
17935 this.inputEl().removeClass(['hide', 'x-hidden']);
17936 this.inputEl().dom.removeAttribute('tabIndex');
17937 this.inputEl().focus();
17939 Roo.log('editor - hiding textarea');
17941 // Roo.log(this.pushValue());
17944 this.inputEl().addClass(['hide', 'x-hidden']);
17945 this.inputEl().dom.setAttribute('tabIndex', -1);
17946 //this.deferFocus();
17949 if(this.resizable){
17950 this.setSize(this.wrap.getSize());
17953 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
17956 // private (for BoxComponent)
17957 adjustSize : Roo.BoxComponent.prototype.adjustSize,
17959 // private (for BoxComponent)
17960 getResizeEl : function(){
17964 // private (for BoxComponent)
17965 getPositionEl : function(){
17970 initEvents : function(){
17971 this.originalValue = this.getValue();
17975 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17978 // markInvalid : Roo.emptyFn,
17980 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17983 // clearInvalid : Roo.emptyFn,
17985 setValue : function(v){
17986 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
17987 this.editorcore.pushValue();
17992 deferFocus : function(){
17993 this.focus.defer(10, this);
17997 focus : function(){
17998 this.editorcore.focus();
18004 onDestroy : function(){
18010 for (var i =0; i < this.toolbars.length;i++) {
18011 // fixme - ask toolbars for heights?
18012 this.toolbars[i].onDestroy();
18015 this.wrap.dom.innerHTML = '';
18016 this.wrap.remove();
18021 onFirstFocus : function(){
18022 //Roo.log("onFirstFocus");
18023 this.editorcore.onFirstFocus();
18024 for (var i =0; i < this.toolbars.length;i++) {
18025 this.toolbars[i].onFirstFocus();
18031 syncValue : function()
18033 this.editorcore.syncValue();
18036 pushValue : function()
18038 this.editorcore.pushValue();
18042 // hide stuff that is not compatible
18056 * @event specialkey
18060 * @cfg {String} fieldClass @hide
18063 * @cfg {String} focusClass @hide
18066 * @cfg {String} autoCreate @hide
18069 * @cfg {String} inputType @hide
18072 * @cfg {String} invalidClass @hide
18075 * @cfg {String} invalidText @hide
18078 * @cfg {String} msgFx @hide
18081 * @cfg {String} validateOnBlur @hide
18090 Roo.namespace('Roo.bootstrap.htmleditor');
18092 * @class Roo.bootstrap.HtmlEditorToolbar1
18097 new Roo.bootstrap.HtmlEditor({
18100 new Roo.bootstrap.HtmlEditorToolbar1({
18101 disable : { fonts: 1 , format: 1, ..., ... , ...],
18107 * @cfg {Object} disable List of elements to disable..
18108 * @cfg {Array} btns List of additional buttons.
18112 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
18115 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
18118 Roo.apply(this, config);
18120 // default disabled, based on 'good practice'..
18121 this.disable = this.disable || {};
18122 Roo.applyIf(this.disable, {
18125 specialElements : true
18127 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18129 this.editor = config.editor;
18130 this.editorcore = config.editor.editorcore;
18132 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18134 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18135 // dont call parent... till later.
18137 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
18142 editorcore : false,
18147 "h1","h2","h3","h4","h5","h6",
18149 "abbr", "acronym", "address", "cite", "samp", "var",
18153 onRender : function(ct, position)
18155 // Roo.log("Call onRender: " + this.xtype);
18157 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18159 this.el.dom.style.marginBottom = '0';
18161 var editorcore = this.editorcore;
18162 var editor= this.editor;
18165 var btn = function(id,cmd , toggle, handler){
18167 var event = toggle ? 'toggle' : 'click';
18172 xns: Roo.bootstrap,
18175 enableToggle:toggle !== false,
18177 pressed : toggle ? false : null,
18180 a.listeners[toggle ? 'toggle' : 'click'] = function() {
18181 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
18190 xns: Roo.bootstrap,
18191 glyphicon : 'font',
18195 xns: Roo.bootstrap,
18199 Roo.each(this.formats, function(f) {
18200 style.menu.items.push({
18202 xns: Roo.bootstrap,
18203 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18208 editorcore.insertTag(this.tagname);
18215 children.push(style);
18218 btn('bold',false,true);
18219 btn('italic',false,true);
18220 btn('align-left', 'justifyleft',true);
18221 btn('align-center', 'justifycenter',true);
18222 btn('align-right' , 'justifyright',true);
18223 btn('link', false, false, function(btn) {
18224 //Roo.log("create link?");
18225 var url = prompt(this.createLinkText, this.defaultLinkValue);
18226 if(url && url != 'http:/'+'/'){
18227 this.editorcore.relayCmd('createlink', url);
18230 btn('list','insertunorderedlist',true);
18231 btn('pencil', false,true, function(btn){
18234 this.toggleSourceEdit(btn.pressed);
18240 xns: Roo.bootstrap,
18245 xns: Roo.bootstrap,
18250 cog.menu.items.push({
18252 xns: Roo.bootstrap,
18253 html : Clean styles,
18258 editorcore.insertTag(this.tagname);
18267 this.xtype = 'NavSimplebar';
18269 for(var i=0;i< children.length;i++) {
18271 this.buttons.add(this.addxtypeChild(children[i]));
18275 editor.on('editorevent', this.updateToolbar, this);
18277 onBtnClick : function(id)
18279 this.editorcore.relayCmd(id);
18280 this.editorcore.focus();
18284 * Protected method that will not generally be called directly. It triggers
18285 * a toolbar update by reading the markup state of the current selection in the editor.
18287 updateToolbar: function(){
18289 if(!this.editorcore.activated){
18290 this.editor.onFirstFocus(); // is this neeed?
18294 var btns = this.buttons;
18295 var doc = this.editorcore.doc;
18296 btns.get('bold').setActive(doc.queryCommandState('bold'));
18297 btns.get('italic').setActive(doc.queryCommandState('italic'));
18298 //btns.get('underline').setActive(doc.queryCommandState('underline'));
18300 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18301 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18302 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18304 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18305 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18308 var ans = this.editorcore.getAllAncestors();
18309 if (this.formatCombo) {
18312 var store = this.formatCombo.store;
18313 this.formatCombo.setValue("");
18314 for (var i =0; i < ans.length;i++) {
18315 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18317 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18325 // hides menus... - so this cant be on a menu...
18326 Roo.bootstrap.MenuMgr.hideAll();
18328 Roo.bootstrap.MenuMgr.hideAll();
18329 //this.editorsyncValue();
18331 onFirstFocus: function() {
18332 this.buttons.each(function(item){
18336 toggleSourceEdit : function(sourceEditMode){
18339 if(sourceEditMode){
18340 Roo.log("disabling buttons");
18341 this.buttons.each( function(item){
18342 if(item.cmd != 'pencil'){
18348 Roo.log("enabling buttons");
18349 if(this.editorcore.initialized){
18350 this.buttons.each( function(item){
18356 Roo.log("calling toggole on editor");
18357 // tell the editor that it's been pressed..
18358 this.editor.toggleSourceEdit(sourceEditMode);
18368 * @class Roo.bootstrap.Table.AbstractSelectionModel
18369 * @extends Roo.util.Observable
18370 * Abstract base class for grid SelectionModels. It provides the interface that should be
18371 * implemented by descendant classes. This class should not be directly instantiated.
18374 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18375 this.locked = false;
18376 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18380 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
18381 /** @ignore Called by the grid automatically. Do not call directly. */
18382 init : function(grid){
18388 * Locks the selections.
18391 this.locked = true;
18395 * Unlocks the selections.
18397 unlock : function(){
18398 this.locked = false;
18402 * Returns true if the selections are locked.
18403 * @return {Boolean}
18405 isLocked : function(){
18406 return this.locked;
18410 * @extends Roo.bootstrap.Table.AbstractSelectionModel
18411 * @class Roo.bootstrap.Table.RowSelectionModel
18412 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18413 * It supports multiple selections and keyboard selection/navigation.
18415 * @param {Object} config
18418 Roo.bootstrap.Table.RowSelectionModel = function(config){
18419 Roo.apply(this, config);
18420 this.selections = new Roo.util.MixedCollection(false, function(o){
18425 this.lastActive = false;
18429 * @event selectionchange
18430 * Fires when the selection changes
18431 * @param {SelectionModel} this
18433 "selectionchange" : true,
18435 * @event afterselectionchange
18436 * Fires after the selection changes (eg. by key press or clicking)
18437 * @param {SelectionModel} this
18439 "afterselectionchange" : true,
18441 * @event beforerowselect
18442 * Fires when a row is selected being selected, return false to cancel.
18443 * @param {SelectionModel} this
18444 * @param {Number} rowIndex The selected index
18445 * @param {Boolean} keepExisting False if other selections will be cleared
18447 "beforerowselect" : true,
18450 * Fires when a row is selected.
18451 * @param {SelectionModel} this
18452 * @param {Number} rowIndex The selected index
18453 * @param {Roo.data.Record} r The record
18455 "rowselect" : true,
18457 * @event rowdeselect
18458 * Fires when a row is deselected.
18459 * @param {SelectionModel} this
18460 * @param {Number} rowIndex The selected index
18462 "rowdeselect" : true
18464 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18465 this.locked = false;
18468 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
18470 * @cfg {Boolean} singleSelect
18471 * True to allow selection of only one row at a time (defaults to false)
18473 singleSelect : false,
18476 initEvents : function(){
18478 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18479 this.grid.on("mousedown", this.handleMouseDown, this);
18480 }else{ // allow click to work like normal
18481 this.grid.on("rowclick", this.handleDragableRowClick, this);
18484 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18485 "up" : function(e){
18487 this.selectPrevious(e.shiftKey);
18488 }else if(this.last !== false && this.lastActive !== false){
18489 var last = this.last;
18490 this.selectRange(this.last, this.lastActive-1);
18491 this.grid.getView().focusRow(this.lastActive);
18492 if(last !== false){
18496 this.selectFirstRow();
18498 this.fireEvent("afterselectionchange", this);
18500 "down" : function(e){
18502 this.selectNext(e.shiftKey);
18503 }else if(this.last !== false && this.lastActive !== false){
18504 var last = this.last;
18505 this.selectRange(this.last, this.lastActive+1);
18506 this.grid.getView().focusRow(this.lastActive);
18507 if(last !== false){
18511 this.selectFirstRow();
18513 this.fireEvent("afterselectionchange", this);
18518 var view = this.grid.view;
18519 view.on("refresh", this.onRefresh, this);
18520 view.on("rowupdated", this.onRowUpdated, this);
18521 view.on("rowremoved", this.onRemove, this);
18525 onRefresh : function(){
18526 var ds = this.grid.dataSource, i, v = this.grid.view;
18527 var s = this.selections;
18528 s.each(function(r){
18529 if((i = ds.indexOfId(r.id)) != -1){
18538 onRemove : function(v, index, r){
18539 this.selections.remove(r);
18543 onRowUpdated : function(v, index, r){
18544 if(this.isSelected(r)){
18545 v.onRowSelect(index);
18551 * @param {Array} records The records to select
18552 * @param {Boolean} keepExisting (optional) True to keep existing selections
18554 selectRecords : function(records, keepExisting){
18556 this.clearSelections();
18558 var ds = this.grid.dataSource;
18559 for(var i = 0, len = records.length; i < len; i++){
18560 this.selectRow(ds.indexOf(records[i]), true);
18565 * Gets the number of selected rows.
18568 getCount : function(){
18569 return this.selections.length;
18573 * Selects the first row in the grid.
18575 selectFirstRow : function(){
18580 * Select the last row.
18581 * @param {Boolean} keepExisting (optional) True to keep existing selections
18583 selectLastRow : function(keepExisting){
18584 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18588 * Selects the row immediately following the last selected row.
18589 * @param {Boolean} keepExisting (optional) True to keep existing selections
18591 selectNext : function(keepExisting){
18592 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18593 this.selectRow(this.last+1, keepExisting);
18594 this.grid.getView().focusRow(this.last);
18599 * Selects the row that precedes the last selected row.
18600 * @param {Boolean} keepExisting (optional) True to keep existing selections
18602 selectPrevious : function(keepExisting){
18604 this.selectRow(this.last-1, keepExisting);
18605 this.grid.getView().focusRow(this.last);
18610 * Returns the selected records
18611 * @return {Array} Array of selected records
18613 getSelections : function(){
18614 return [].concat(this.selections.items);
18618 * Returns the first selected record.
18621 getSelected : function(){
18622 return this.selections.itemAt(0);
18627 * Clears all selections.
18629 clearSelections : function(fast){
18630 if(this.locked) return;
18632 var ds = this.grid.dataSource;
18633 var s = this.selections;
18634 s.each(function(r){
18635 this.deselectRow(ds.indexOfId(r.id));
18639 this.selections.clear();
18646 * Selects all rows.
18648 selectAll : function(){
18649 if(this.locked) return;
18650 this.selections.clear();
18651 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18652 this.selectRow(i, true);
18657 * Returns True if there is a selection.
18658 * @return {Boolean}
18660 hasSelection : function(){
18661 return this.selections.length > 0;
18665 * Returns True if the specified row is selected.
18666 * @param {Number/Record} record The record or index of the record to check
18667 * @return {Boolean}
18669 isSelected : function(index){
18670 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18671 return (r && this.selections.key(r.id) ? true : false);
18675 * Returns True if the specified record id is selected.
18676 * @param {String} id The id of record to check
18677 * @return {Boolean}
18679 isIdSelected : function(id){
18680 return (this.selections.key(id) ? true : false);
18684 handleMouseDown : function(e, t){
18685 var view = this.grid.getView(), rowIndex;
18686 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18689 if(e.shiftKey && this.last !== false){
18690 var last = this.last;
18691 this.selectRange(last, rowIndex, e.ctrlKey);
18692 this.last = last; // reset the last
18693 view.focusRow(rowIndex);
18695 var isSelected = this.isSelected(rowIndex);
18696 if(e.button !== 0 && isSelected){
18697 view.focusRow(rowIndex);
18698 }else if(e.ctrlKey && isSelected){
18699 this.deselectRow(rowIndex);
18700 }else if(!isSelected){
18701 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18702 view.focusRow(rowIndex);
18705 this.fireEvent("afterselectionchange", this);
18708 handleDragableRowClick : function(grid, rowIndex, e)
18710 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18711 this.selectRow(rowIndex, false);
18712 grid.view.focusRow(rowIndex);
18713 this.fireEvent("afterselectionchange", this);
18718 * Selects multiple rows.
18719 * @param {Array} rows Array of the indexes of the row to select
18720 * @param {Boolean} keepExisting (optional) True to keep existing selections
18722 selectRows : function(rows, keepExisting){
18724 this.clearSelections();
18726 for(var i = 0, len = rows.length; i < len; i++){
18727 this.selectRow(rows[i], true);
18732 * Selects a range of rows. All rows in between startRow and endRow are also selected.
18733 * @param {Number} startRow The index of the first row in the range
18734 * @param {Number} endRow The index of the last row in the range
18735 * @param {Boolean} keepExisting (optional) True to retain existing selections
18737 selectRange : function(startRow, endRow, keepExisting){
18738 if(this.locked) return;
18740 this.clearSelections();
18742 if(startRow <= endRow){
18743 for(var i = startRow; i <= endRow; i++){
18744 this.selectRow(i, true);
18747 for(var i = startRow; i >= endRow; i--){
18748 this.selectRow(i, true);
18754 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18755 * @param {Number} startRow The index of the first row in the range
18756 * @param {Number} endRow The index of the last row in the range
18758 deselectRange : function(startRow, endRow, preventViewNotify){
18759 if(this.locked) return;
18760 for(var i = startRow; i <= endRow; i++){
18761 this.deselectRow(i, preventViewNotify);
18767 * @param {Number} row The index of the row to select
18768 * @param {Boolean} keepExisting (optional) True to keep existing selections
18770 selectRow : function(index, keepExisting, preventViewNotify){
18771 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18772 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18773 if(!keepExisting || this.singleSelect){
18774 this.clearSelections();
18776 var r = this.grid.dataSource.getAt(index);
18777 this.selections.add(r);
18778 this.last = this.lastActive = index;
18779 if(!preventViewNotify){
18780 this.grid.getView().onRowSelect(index);
18782 this.fireEvent("rowselect", this, index, r);
18783 this.fireEvent("selectionchange", this);
18789 * @param {Number} row The index of the row to deselect
18791 deselectRow : function(index, preventViewNotify){
18792 if(this.locked) return;
18793 if(this.last == index){
18796 if(this.lastActive == index){
18797 this.lastActive = false;
18799 var r = this.grid.dataSource.getAt(index);
18800 this.selections.remove(r);
18801 if(!preventViewNotify){
18802 this.grid.getView().onRowDeselect(index);
18804 this.fireEvent("rowdeselect", this, index);
18805 this.fireEvent("selectionchange", this);
18809 restoreLast : function(){
18811 this.last = this._last;
18816 acceptsNav : function(row, col, cm){
18817 return !cm.isHidden(col) && cm.isCellEditable(col, row);
18821 onEditorKey : function(field, e){
18822 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18827 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18829 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18831 }else if(k == e.ENTER && !e.ctrlKey){
18835 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18837 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18839 }else if(k == e.ESC){
18843 g.startEditing(newCell[0], newCell[1]);
18848 * Ext JS Library 1.1.1
18849 * Copyright(c) 2006-2007, Ext JS, LLC.
18851 * Originally Released Under LGPL - original licence link has changed is not relivant.
18854 * <script type="text/javascript">
18858 * @class Roo.bootstrap.PagingToolbar
18860 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18862 * Create a new PagingToolbar
18863 * @param {Object} config The config object
18865 Roo.bootstrap.PagingToolbar = function(config)
18867 // old args format still supported... - xtype is prefered..
18868 // created from xtype...
18869 var ds = config.dataSource;
18870 this.toolbarItems = [];
18871 if (config.items) {
18872 this.toolbarItems = config.items;
18873 // config.items = [];
18876 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18883 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18887 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18889 * @cfg {Roo.data.Store} dataSource
18890 * The underlying data store providing the paged data
18893 * @cfg {String/HTMLElement/Element} container
18894 * container The id or element that will contain the toolbar
18897 * @cfg {Boolean} displayInfo
18898 * True to display the displayMsg (defaults to false)
18901 * @cfg {Number} pageSize
18902 * The number of records to display per page (defaults to 20)
18906 * @cfg {String} displayMsg
18907 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18909 displayMsg : 'Displaying {0} - {1} of {2}',
18911 * @cfg {String} emptyMsg
18912 * The message to display when no records are found (defaults to "No data to display")
18914 emptyMsg : 'No data to display',
18916 * Customizable piece of the default paging text (defaults to "Page")
18919 beforePageText : "Page",
18921 * Customizable piece of the default paging text (defaults to "of %0")
18924 afterPageText : "of {0}",
18926 * Customizable piece of the default paging text (defaults to "First Page")
18929 firstText : "First Page",
18931 * Customizable piece of the default paging text (defaults to "Previous Page")
18934 prevText : "Previous Page",
18936 * Customizable piece of the default paging text (defaults to "Next Page")
18939 nextText : "Next Page",
18941 * Customizable piece of the default paging text (defaults to "Last Page")
18944 lastText : "Last Page",
18946 * Customizable piece of the default paging text (defaults to "Refresh")
18949 refreshText : "Refresh",
18953 onRender : function(ct, position)
18955 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
18956 this.navgroup.parentId = this.id;
18957 this.navgroup.onRender(this.el, null);
18958 // add the buttons to the navgroup
18960 if(this.displayInfo){
18961 Roo.log(this.el.select('ul.navbar-nav',true).first());
18962 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
18963 this.displayEl = this.el.select('.x-paging-info', true).first();
18964 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
18965 // this.displayEl = navel.el.select('span',true).first();
18971 Roo.each(_this.buttons, function(e){
18972 Roo.factory(e).onRender(_this.el, null);
18976 Roo.each(_this.toolbarItems, function(e) {
18977 _this.navgroup.addItem(e);
18980 this.first = this.navgroup.addItem({
18981 tooltip: this.firstText,
18983 icon : 'fa fa-backward',
18985 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
18988 this.prev = this.navgroup.addItem({
18989 tooltip: this.prevText,
18991 icon : 'fa fa-step-backward',
18993 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
18995 //this.addSeparator();
18998 var field = this.navgroup.addItem( {
19000 cls : 'x-paging-position',
19002 html : this.beforePageText +
19003 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
19004 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
19007 this.field = field.el.select('input', true).first();
19008 this.field.on("keydown", this.onPagingKeydown, this);
19009 this.field.on("focus", function(){this.dom.select();});
19012 this.afterTextEl = field.el.select('.x-paging-after',true).first();
19013 //this.field.setHeight(18);
19014 //this.addSeparator();
19015 this.next = this.navgroup.addItem({
19016 tooltip: this.nextText,
19018 html : ' <i class="fa fa-step-forward">',
19020 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
19022 this.last = this.navgroup.addItem({
19023 tooltip: this.lastText,
19024 icon : 'fa fa-forward',
19027 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
19029 //this.addSeparator();
19030 this.loading = this.navgroup.addItem({
19031 tooltip: this.refreshText,
19032 icon: 'fa fa-refresh',
19034 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
19040 updateInfo : function(){
19041 if(this.displayEl){
19042 var count = this.ds.getCount();
19043 var msg = count == 0 ?
19047 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
19049 this.displayEl.update(msg);
19054 onLoad : function(ds, r, o){
19055 this.cursor = o.params ? o.params.start : 0;
19056 var d = this.getPageData(),
19060 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
19061 this.field.dom.value = ap;
19062 this.first.setDisabled(ap == 1);
19063 this.prev.setDisabled(ap == 1);
19064 this.next.setDisabled(ap == ps);
19065 this.last.setDisabled(ap == ps);
19066 this.loading.enable();
19071 getPageData : function(){
19072 var total = this.ds.getTotalCount();
19075 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
19076 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
19081 onLoadError : function(){
19082 this.loading.enable();
19086 onPagingKeydown : function(e){
19087 var k = e.getKey();
19088 var d = this.getPageData();
19090 var v = this.field.dom.value, pageNum;
19091 if(!v || isNaN(pageNum = parseInt(v, 10))){
19092 this.field.dom.value = d.activePage;
19095 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
19096 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19099 else if(k == e.HOME || (k == e.UP && e.ctrlKey) || (k == e.PAGEUP && e.ctrlKey) || (k == e.RIGHT && e.ctrlKey) || k == e.END || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey))
19101 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
19102 this.field.dom.value = pageNum;
19103 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
19106 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19108 var v = this.field.dom.value, pageNum;
19109 var increment = (e.shiftKey) ? 10 : 1;
19110 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19112 if(!v || isNaN(pageNum = parseInt(v, 10))) {
19113 this.field.dom.value = d.activePage;
19116 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
19118 this.field.dom.value = parseInt(v, 10) + increment;
19119 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
19120 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19127 beforeLoad : function(){
19129 this.loading.disable();
19134 onClick : function(which){
19141 ds.load({params:{start: 0, limit: this.pageSize}});
19144 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19147 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19150 var total = ds.getTotalCount();
19151 var extra = total % this.pageSize;
19152 var lastStart = extra ? (total - extra) : total-this.pageSize;
19153 ds.load({params:{start: lastStart, limit: this.pageSize}});
19156 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19162 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19163 * @param {Roo.data.Store} store The data store to unbind
19165 unbind : function(ds){
19166 ds.un("beforeload", this.beforeLoad, this);
19167 ds.un("load", this.onLoad, this);
19168 ds.un("loadexception", this.onLoadError, this);
19169 ds.un("remove", this.updateInfo, this);
19170 ds.un("add", this.updateInfo, this);
19171 this.ds = undefined;
19175 * Binds the paging toolbar to the specified {@link Roo.data.Store}
19176 * @param {Roo.data.Store} store The data store to bind
19178 bind : function(ds){
19179 ds.on("beforeload", this.beforeLoad, this);
19180 ds.on("load", this.onLoad, this);
19181 ds.on("loadexception", this.onLoadError, this);
19182 ds.on("remove", this.updateInfo, this);
19183 ds.on("add", this.updateInfo, this);
19194 * @class Roo.bootstrap.MessageBar
19195 * @extends Roo.bootstrap.Component
19196 * Bootstrap MessageBar class
19197 * @cfg {String} html contents of the MessageBar
19198 * @cfg {String} weight (info | success | warning | danger) default info
19199 * @cfg {String} beforeClass insert the bar before the given class
19200 * @cfg {Boolean} closable (true | false) default false
19201 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19204 * Create a new Element
19205 * @param {Object} config The config object
19208 Roo.bootstrap.MessageBar = function(config){
19209 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19212 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
19218 beforeClass: 'bootstrap-sticky-wrap',
19220 getAutoCreate : function(){
19224 cls: 'alert alert-dismissable alert-' + this.weight,
19229 html: this.html || ''
19235 cfg.cls += ' alert-messages-fixed';
19249 onRender : function(ct, position)
19251 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19254 var cfg = Roo.apply({}, this.getAutoCreate());
19258 cfg.cls += ' ' + this.cls;
19261 cfg.style = this.style;
19263 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19265 this.el.setVisibilityMode(Roo.Element.DISPLAY);
19268 this.el.select('>button.close').on('click', this.hide, this);
19274 if (!this.rendered) {
19280 this.fireEvent('show', this);
19286 if (!this.rendered) {
19292 this.fireEvent('hide', this);
19295 update : function()
19297 // var e = this.el.dom.firstChild;
19299 // if(this.closable){
19300 // e = e.nextSibling;
19303 // e.data = this.html || '';
19305 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19321 * @class Roo.bootstrap.Graph
19322 * @extends Roo.bootstrap.Component
19323 * Bootstrap Graph class
19327 @cfg {String} graphtype bar | vbar | pie
19328 @cfg {number} g_x coodinator | centre x (pie)
19329 @cfg {number} g_y coodinator | centre y (pie)
19330 @cfg {number} g_r radius (pie)
19331 @cfg {number} g_height height of the chart (respected by all elements in the set)
19332 @cfg {number} g_width width of the chart (respected by all elements in the set)
19333 @cfg {Object} title The title of the chart
19336 -opts (object) options for the chart
19338 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19339 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19341 o colors (array) colors be used repeatedly to plot the bars. If multicolumn bar is used each sequence of bars with use a different color.
19342 o stacked (boolean) whether or not to tread values as in a stacked bar chart
19344 o stretch (boolean)
19346 -opts (object) options for the pie
19349 o startAngle (number)
19350 o endAngle (number)
19354 * Create a new Input
19355 * @param {Object} config The config object
19358 Roo.bootstrap.Graph = function(config){
19359 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19365 * The img click event for the img.
19366 * @param {Roo.EventObject} e
19372 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
19383 //g_colors: this.colors,
19390 getAutoCreate : function(){
19401 onRender : function(ct,position){
19402 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19403 this.raphael = Raphael(this.el.dom);
19405 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19406 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19407 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19408 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19410 r.text(160, 10, "Single Series Chart").attr(txtattr);
19411 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19412 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19413 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19415 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19416 r.barchart(330, 10, 300, 220, data1);
19417 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19418 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19421 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19422 // r.barchart(30, 30, 560, 250, xdata, {
19423 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19424 // axis : "0 0 1 1",
19425 // axisxlabels : xdata
19426 // //yvalues : cols,
19429 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19431 // this.load(null,xdata,{
19432 // axis : "0 0 1 1",
19433 // axisxlabels : xdata
19438 load : function(graphtype,xdata,opts){
19439 this.raphael.clear();
19441 graphtype = this.graphtype;
19446 var r = this.raphael,
19447 fin = function () {
19448 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19450 fout = function () {
19451 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19453 pfin = function() {
19454 this.sector.stop();
19455 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19458 this.label[0].stop();
19459 this.label[0].attr({ r: 7.5 });
19460 this.label[1].attr({ "font-weight": 800 });
19463 pfout = function() {
19464 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19467 this.label[0].animate({ r: 5 }, 500, "bounce");
19468 this.label[1].attr({ "font-weight": 400 });
19474 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19477 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19480 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
19481 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19483 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19490 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19495 setTitle: function(o)
19500 initEvents: function() {
19503 this.el.on('click', this.onClick, this);
19507 onClick : function(e)
19509 Roo.log('img onclick');
19510 this.fireEvent('click', this, e);
19522 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19525 * @class Roo.bootstrap.dash.NumberBox
19526 * @extends Roo.bootstrap.Component
19527 * Bootstrap NumberBox class
19528 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19529 * @cfg {String} headline Box headline
19530 * @cfg {String} content Box content
19531 * @cfg {String} icon Box icon
19532 * @cfg {String} footer Footer text
19533 * @cfg {String} fhref Footer href
19536 * Create a new NumberBox
19537 * @param {Object} config The config object
19541 Roo.bootstrap.dash.NumberBox = function(config){
19542 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19546 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
19556 getAutoCreate : function(){
19560 cls : 'small-box bg-' + this.bgcolor,
19568 cls : 'roo-headline',
19569 html : this.headline
19573 cls : 'roo-content',
19574 html : this.content
19588 cls : 'ion ' + this.icon
19597 cls : 'small-box-footer',
19598 href : this.fhref || '#',
19602 cfg.cn.push(footer);
19609 onRender : function(ct,position){
19610 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19617 setHeadline: function (value)
19619 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19622 setFooter: function (value, href)
19624 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19627 this.el.select('a.small-box-footer',true).first().attr('href', href);
19632 setContent: function (value)
19634 this.el.select('.roo-content',true).first().dom.innerHTML = value;
19637 initEvents: function()
19651 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19654 * @class Roo.bootstrap.dash.TabBox
19655 * @extends Roo.bootstrap.Component
19656 * Bootstrap TabBox class
19657 * @cfg {String} title Title of the TabBox
19658 * @cfg {String} icon Icon of the TabBox
19659 * @cfg {Boolean} showtabs (true|false) show the tabs default true
19662 * Create a new TabBox
19663 * @param {Object} config The config object
19667 Roo.bootstrap.dash.TabBox = function(config){
19668 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19673 * When a pane is added
19674 * @param {Roo.bootstrap.dash.TabPane} pane
19681 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
19687 getChildContainer : function()
19689 return this.el.select('.tab-content', true).first();
19692 getAutoCreate : function(){
19696 cls: 'pull-left header',
19704 cls: 'fa ' + this.icon
19711 cls: 'nav-tabs-custom',
19715 cls: 'nav nav-tabs pull-right',
19722 cls: 'tab-content no-padding',
19730 initEvents : function()
19732 //Roo.log('add add pane handler');
19733 this.on('addpane', this.onAddPane, this);
19736 * Updates the box title
19737 * @param {String} html to set the title to.
19739 setTitle : function(value)
19741 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
19743 onAddPane : function(pane)
19745 //Roo.log('addpane');
19747 // tabs are rendere left to right..
19748 if(!this.showtabs){
19752 var ctr = this.el.select('.nav-tabs', true).first();
19755 var existing = ctr.select('.nav-tab',true);
19756 var qty = existing.getCount();;
19759 var tab = ctr.createChild({
19761 cls : 'nav-tab' + (qty ? '' : ' active'),
19769 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
19772 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
19774 pane.el.addClass('active');
19779 onTabClick : function(ev,un,ob,pane)
19781 //Roo.log('tab - prev default');
19782 ev.preventDefault();
19785 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
19786 pane.tab.addClass('active');
19787 //Roo.log(pane.title);
19788 this.getChildContainer().select('.tab-pane',true).removeClass('active');
19789 // technically we should have a deactivate event.. but maybe add later.
19790 // and it should not de-activate the selected tab...
19792 pane.el.addClass('active');
19793 pane.fireEvent('activate');
19808 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19810 * @class Roo.bootstrap.TabPane
19811 * @extends Roo.bootstrap.Component
19812 * Bootstrap TabPane class
19813 * @cfg {Boolean} active (false | true) Default false
19814 * @cfg {String} title title of panel
19818 * Create a new TabPane
19819 * @param {Object} config The config object
19822 Roo.bootstrap.dash.TabPane = function(config){
19823 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19829 * When a pane is activated
19830 * @param {Roo.bootstrap.dash.TabPane} pane
19837 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
19842 // the tabBox that this is attached to.
19845 getAutoCreate : function()
19853 cfg.cls += ' active';
19858 initEvents : function()
19860 //Roo.log('trigger add pane handler');
19861 this.parent().fireEvent('addpane', this)
19865 * Updates the tab title
19866 * @param {String} html to set the title to.
19868 setTitle: function(str)
19874 this.tab.select('a', true).first().dom.innerHTML = str;
19891 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19894 * @class Roo.bootstrap.menu.Menu
19895 * @extends Roo.bootstrap.Component
19896 * Bootstrap Menu class - container for Menu
19897 * @cfg {String} html Text of the menu
19898 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19899 * @cfg {String} icon Font awesome icon
19900 * @cfg {String} pos Menu align to (top | bottom) default bottom
19904 * Create a new Menu
19905 * @param {Object} config The config object
19909 Roo.bootstrap.menu.Menu = function(config){
19910 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19914 * @event beforeshow
19915 * Fires before this menu is displayed
19916 * @param {Roo.bootstrap.menu.Menu} this
19920 * @event beforehide
19921 * Fires before this menu is hidden
19922 * @param {Roo.bootstrap.menu.Menu} this
19927 * Fires after this menu is displayed
19928 * @param {Roo.bootstrap.menu.Menu} this
19933 * Fires after this menu is hidden
19934 * @param {Roo.bootstrap.menu.Menu} this
19939 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19940 * @param {Roo.bootstrap.menu.Menu} this
19941 * @param {Roo.EventObject} e
19948 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
19952 weight : 'default',
19957 getChildContainer : function() {
19958 if(this.isSubMenu){
19962 return this.el.select('ul.dropdown-menu', true).first();
19965 getAutoCreate : function()
19970 cls : 'roo-menu-text',
19978 cls : 'fa ' + this.icon
19989 cls : 'dropdown-button btn btn-' + this.weight,
19994 cls : 'dropdown-toggle btn btn-' + this.weight,
20004 cls : 'dropdown-menu'
20010 if(this.pos == 'top'){
20011 cfg.cls += ' dropup';
20014 if(this.isSubMenu){
20017 cls : 'dropdown-menu'
20024 onRender : function(ct, position)
20026 this.isSubMenu = ct.hasClass('dropdown-submenu');
20028 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
20031 initEvents : function()
20033 if(this.isSubMenu){
20037 this.hidden = true;
20039 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
20040 this.triggerEl.on('click', this.onTriggerPress, this);
20042 this.buttonEl = this.el.select('button.dropdown-button', true).first();
20043 this.buttonEl.on('click', this.onClick, this);
20049 if(this.isSubMenu){
20053 return this.el.select('ul.dropdown-menu', true).first();
20056 onClick : function(e)
20058 this.fireEvent("click", this, e);
20061 onTriggerPress : function(e)
20063 if (this.isVisible()) {
20070 isVisible : function(){
20071 return !this.hidden;
20076 this.fireEvent("beforeshow", this);
20078 this.hidden = false;
20079 this.el.addClass('open');
20081 Roo.get(document).on("mouseup", this.onMouseUp, this);
20083 this.fireEvent("show", this);
20090 this.fireEvent("beforehide", this);
20092 this.hidden = true;
20093 this.el.removeClass('open');
20095 Roo.get(document).un("mouseup", this.onMouseUp);
20097 this.fireEvent("hide", this);
20100 onMouseUp : function()
20114 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20117 * @class Roo.bootstrap.menu.Item
20118 * @extends Roo.bootstrap.Component
20119 * Bootstrap MenuItem class
20120 * @cfg {Boolean} submenu (true | false) default false
20121 * @cfg {String} html text of the item
20122 * @cfg {String} href the link
20123 * @cfg {Boolean} disable (true | false) default false
20124 * @cfg {Boolean} preventDefault (true | false) default true
20125 * @cfg {String} icon Font awesome icon
20126 * @cfg {String} pos Submenu align to (left | right) default right
20130 * Create a new Item
20131 * @param {Object} config The config object
20135 Roo.bootstrap.menu.Item = function(config){
20136 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20140 * Fires when the mouse is hovering over this menu
20141 * @param {Roo.bootstrap.menu.Item} this
20142 * @param {Roo.EventObject} e
20147 * Fires when the mouse exits this menu
20148 * @param {Roo.bootstrap.menu.Item} this
20149 * @param {Roo.EventObject} e
20155 * The raw click event for the entire grid.
20156 * @param {Roo.EventObject} e
20162 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
20167 preventDefault: true,
20172 getAutoCreate : function()
20177 cls : 'roo-menu-item-text',
20185 cls : 'fa ' + this.icon
20194 href : this.href || '#',
20201 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20205 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20207 if(this.pos == 'left'){
20208 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20215 initEvents : function()
20217 this.el.on('mouseover', this.onMouseOver, this);
20218 this.el.on('mouseout', this.onMouseOut, this);
20220 this.el.select('a', true).first().on('click', this.onClick, this);
20224 onClick : function(e)
20226 if(this.preventDefault){
20227 e.preventDefault();
20230 this.fireEvent("click", this, e);
20233 onMouseOver : function(e)
20235 if(this.submenu && this.pos == 'left'){
20236 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20239 this.fireEvent("mouseover", this, e);
20242 onMouseOut : function(e)
20244 this.fireEvent("mouseout", this, e);
20256 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20259 * @class Roo.bootstrap.menu.Separator
20260 * @extends Roo.bootstrap.Component
20261 * Bootstrap Separator class
20264 * Create a new Separator
20265 * @param {Object} config The config object
20269 Roo.bootstrap.menu.Separator = function(config){
20270 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20273 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
20275 getAutoCreate : function(){