4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
21 * Do not use directly - it does not do anything..
22 * @param {Object} config The config object
27 Roo.bootstrap.Component = function(config){
28 Roo.bootstrap.Component.superclass.constructor.call(this, config);
31 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
34 allowDomMove : false, // to stop relocations in parent onRender...
42 initEvents : function() { },
48 can_build_overlaid : true,
55 // returns the parent component..
56 return Roo.ComponentMgr.get(this.parentId)
62 onRender : function(ct, position)
64 // Roo.log("Call onRender: " + this.xtype);
66 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
69 if (this.el.attr('xtype')) {
70 this.el.attr('xtypex', this.el.attr('xtype'));
71 this.el.dom.removeAttribute('xtype');
81 var cfg = Roo.apply({}, this.getAutoCreate());
84 // fill in the extra attributes
85 if (this.xattr && typeof(this.xattr) =='object') {
86 for (var i in this.xattr) {
87 cfg[i] = this.xattr[i];
92 cfg.dataId = this.dataId;
96 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
99 if (this.style) { // fixme needs to support more complex style data.
100 cfg.style = this.style;
104 cfg.name = this.name;
107 this.el = ct.createChild(cfg, position);
109 if(this.tabIndex !== undefined){
110 this.el.dom.setAttribute('tabIndex', this.tabIndex);
117 getChildContainer : function()
123 addxtype : function(tree,cntr)
127 cn = Roo.factory(tree);
129 cn.parentType = this.xtype; //??
130 cn.parentId = this.id;
132 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
134 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
136 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
138 var build_from_html = Roo.XComponent.build_from_html;
140 var is_body = (tree.xtype == 'Body') ;
142 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
144 var self_cntr_el = Roo.get(this[cntr]());
146 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
147 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
148 return this.addxtypeChild(tree,cntr);
151 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
154 return this.addxtypeChild(Roo.apply({}, tree),cntr);
157 Roo.log('skipping render');
165 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
171 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
175 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
180 addxtypeChild : function (tree, cntr)
182 Roo.log('addxtypeChild:' + cntr);
184 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
187 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
188 (typeof(tree['flexy:foreach']) != 'undefined');
193 // render the element if it's not BODY.
194 if (tree.xtype != 'Body') {
196 cn = Roo.factory(tree);
198 cn.parentType = this.xtype; //??
199 cn.parentId = this.id;
201 var build_from_html = Roo.XComponent.build_from_html;
204 // does the container contain child eleemnts with 'xtype' attributes.
205 // that match this xtype..
206 // note - when we render we create these as well..
207 // so we should check to see if body has xtype set.
208 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
210 var self_cntr_el = Roo.get(this[cntr]());
211 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
213 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
214 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
220 //echild.dom.removeAttribute('xtype');
222 Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
229 // if object has flexy:if - then it may or may not be rendered.
230 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
231 // skip a flexy if element.
232 Roo.log('skipping render');
235 // actually if flexy:foreach is found, we really want to create
236 // multiple copies here...
238 //Roo.log(this[cntr]());
239 cn.render(this[cntr]());
241 // then add the element..
248 if (typeof (tree.menu) != 'undefined') {
249 tree.menu.parentType = cn.xtype;
250 tree.menu.triggerEl = cn.el;
251 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
255 if (!tree.items || !tree.items.length) {
259 var items = tree.items;
262 //Roo.log(items.length);
264 for(var i =0;i < items.length;i++) {
265 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
286 * @class Roo.bootstrap.Body
287 * @extends Roo.bootstrap.Component
288 * Bootstrap Body class
292 * @param {Object} config The config object
295 Roo.bootstrap.Body = function(config){
296 Roo.bootstrap.Body.superclass.constructor.call(this, config);
297 this.el = Roo.get(document.body);
298 if (this.cls && this.cls.length) {
299 Roo.get(document.body).addClass(this.cls);
303 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
308 onRender : function(ct, position)
310 /* Roo.log("Roo.bootstrap.Body - onRender");
311 if (this.cls && this.cls.length) {
312 Roo.get(document.body).addClass(this.cls);
332 * @class Roo.bootstrap.ButtonGroup
333 * @extends Roo.bootstrap.Component
334 * Bootstrap ButtonGroup class
335 * @cfg {String} size lg | sm | xs (default empty normal)
336 * @cfg {String} align vertical | justified (default none)
337 * @cfg {String} direction up | down (default down)
338 * @cfg {Boolean} toolbar false | true
339 * @cfg {Boolean} btn true | false
344 * @param {Object} config The config object
347 Roo.bootstrap.ButtonGroup = function(config){
348 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
351 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
359 getAutoCreate : function(){
365 cfg.html = this.html || cfg.html;
376 if (['vertical','justified'].indexOf(this.align)!==-1) {
377 cfg.cls = 'btn-group-' + this.align;
379 if (this.align == 'justified') {
380 console.log(this.items);
384 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
385 cfg.cls += ' btn-group-' + this.size;
388 if (this.direction == 'up') {
389 cfg.cls += ' dropup' ;
405 * @class Roo.bootstrap.Button
406 * @extends Roo.bootstrap.Component
407 * Bootstrap Button class
408 * @cfg {String} html The button content
409 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger | link
410 * @cfg {String} size empty | lg | sm | xs
411 * @cfg {String} tag empty | a | input | submit
412 * @cfg {String} href empty or href
413 * @cfg {Boolean} disabled false | true
414 * @cfg {Boolean} isClose false | true
415 * @cfg {String} glyphicon empty | adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out
416 * @cfg {String} badge text for badge
417 * @cfg {String} theme default (or empty) | glow
418 * @cfg {Boolean} inverse false | true
419 * @cfg {Boolean} toggle false | true
420 * @cfg {String} ontext text for on toggle state
421 * @cfg {String} offtext text for off toggle state
422 * @cfg {Boolean} defaulton true | false
423 * @cfg {Boolean} preventDefault (true | false) default true
424 * @cfg {Boolean} removeClass true | false remove the standard class..
425 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
428 * Create a new button
429 * @param {Object} config The config object
433 Roo.bootstrap.Button = function(config){
434 Roo.bootstrap.Button.superclass.constructor.call(this, config);
439 * When a butotn is pressed
440 * @param {Roo.EventObject} e
445 * After the button has been toggles
446 * @param {Roo.EventObject} e
447 * @param {boolean} pressed (also available as button.pressed)
453 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
471 preventDefault: true,
480 getAutoCreate : function(){
488 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
489 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
494 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
496 if (this.toggle == true) {
499 cls: 'slider-frame roo-button',
504 'data-off-text':'OFF',
505 cls: 'slider-button',
511 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
512 cfg.cls += ' '+this.weight;
521 cfg["aria-hidden"] = true;
523 cfg.html = "×";
529 if (this.theme==='default') {
530 cfg.cls = 'btn roo-button';
532 //if (this.parentType != 'Navbar') {
533 this.weight = this.weight.length ? this.weight : 'default';
535 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
537 cfg.cls += ' btn-' + this.weight;
539 } else if (this.theme==='glow') {
542 cfg.cls = 'btn-glow roo-button';
544 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
546 cfg.cls += ' ' + this.weight;
552 this.cls += ' inverse';
557 cfg.cls += ' active';
561 cfg.disabled = 'disabled';
565 Roo.log('changing to ul' );
567 this.glyphicon = 'caret';
570 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
572 //gsRoo.log(this.parentType);
573 if (this.parentType === 'Navbar' && !this.parent().bar) {
574 Roo.log('changing to li?');
583 href : this.href || '#'
586 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
587 cfg.cls += ' dropdown';
594 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
596 if (this.glyphicon) {
597 cfg.html = ' ' + cfg.html;
602 cls: 'glyphicon glyphicon-' + this.glyphicon
612 // cfg.cls='btn roo-button';
616 var value = cfg.html;
621 cls: 'glyphicon glyphicon-' + this.glyphicon,
640 cfg.cls += ' dropdown';
641 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
644 if (cfg.tag !== 'a' && this.href !== '') {
645 throw "Tag must be a to set href.";
646 } else if (this.href.length > 0) {
647 cfg.href = this.href;
650 if(this.removeClass){
655 cfg.target = this.target;
660 initEvents: function() {
661 // Roo.log('init events?');
662 // Roo.log(this.el.dom);
663 if (this.el.hasClass('roo-button')) {
664 this.el.on('click', this.onClick, this);
666 this.el.select('.roo-button').on('click', this.onClick, this);
669 if(this.removeClass){
670 this.el.on('click', this.onClick, this);
673 this.el.enableDisplayMode();
676 onClick : function(e)
682 Roo.log('button on click ');
683 if(this.preventDefault){
686 if (this.pressed === true || this.pressed === false) {
687 this.pressed = !this.pressed;
688 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
689 this.fireEvent('toggle', this, e, this.pressed);
693 this.fireEvent('click', this, e);
697 * Enables this button
701 this.disabled = false;
702 this.el.removeClass('disabled');
706 * Disable this button
710 this.disabled = true;
711 this.el.addClass('disabled');
714 * sets the active state on/off,
715 * @param {Boolean} state (optional) Force a particular state
717 setActive : function(v) {
719 this.el[v ? 'addClass' : 'removeClass']('active');
722 * toggles the current active state
724 toggleActive : function()
726 var active = this.el.hasClass('active');
727 this.setActive(!active);
731 setText : function(str)
733 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
756 * @class Roo.bootstrap.Column
757 * @extends Roo.bootstrap.Component
758 * Bootstrap Column class
759 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
760 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
761 * @cfg {Number} md colspan out of 12 for computer-sized screens
762 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
763 * @cfg {String} html content of column.
766 * Create a new Column
767 * @param {Object} config The config object
770 Roo.bootstrap.Column = function(config){
771 Roo.bootstrap.Column.superclass.constructor.call(this, config);
774 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
783 getAutoCreate : function(){
784 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
792 ['xs','sm','md','lg'].map(function(size){
793 if (settings[size]) {
794 cfg.cls += ' col-' + size + '-' + settings[size];
797 if (this.html.length) {
798 cfg.html = this.html;
817 * @class Roo.bootstrap.Container
818 * @extends Roo.bootstrap.Component
819 * Bootstrap Container class
820 * @cfg {Boolean} jumbotron is it a jumbotron element
821 * @cfg {String} html content of element
822 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
823 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
824 * @cfg {String} header content of header (for panel)
825 * @cfg {String} footer content of footer (for panel)
826 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
827 * @cfg {String} tag (header|aside|section) type of HTML tag.
831 * Create a new Container
832 * @param {Object} config The config object
835 Roo.bootstrap.Container = function(config){
836 Roo.bootstrap.Container.superclass.constructor.call(this, config);
839 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
850 getChildContainer : function() {
856 if (this.panel.length) {
857 return this.el.select('.panel-body',true).first();
864 getAutoCreate : function(){
867 tag : this.tag || 'div',
871 if (this.jumbotron) {
872 cfg.cls = 'jumbotron';
874 // - this is applied by the parent..
876 // cfg.cls = this.cls + '';
879 if (this.sticky.length) {
881 var bd = Roo.get(document.body);
882 if (!bd.hasClass('bootstrap-sticky')) {
883 bd.addClass('bootstrap-sticky');
884 Roo.select('html',true).setStyle('height', '100%');
887 cfg.cls += 'bootstrap-sticky-' + this.sticky;
891 if (this.well.length) {
895 cfg.cls +=' well well-' +this.well;
905 if (this.panel.length) {
906 cfg.cls += ' panel panel-' + this.panel;
908 if (this.header.length) {
911 cls : 'panel-heading',
927 if (this.footer.length) {
929 cls : 'panel-footer',
937 body.html = this.html || cfg.html;
939 if (!this.cls || !this.cls.length) {
940 cfg.cls = 'container';
957 * @class Roo.bootstrap.Img
958 * @extends Roo.bootstrap.Component
959 * Bootstrap Img class
960 * @cfg {Boolean} imgResponsive false | true
961 * @cfg {String} border rounded | circle | thumbnail
962 * @cfg {String} src image source
963 * @cfg {String} alt image alternative text
964 * @cfg {String} href a tag href
965 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
969 * @param {Object} config The config object
972 Roo.bootstrap.Img = function(config){
973 Roo.bootstrap.Img.superclass.constructor.call(this, config);
979 * The img click event for the img.
980 * @param {Roo.EventObject} e
986 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
994 getAutoCreate : function(){
998 cls: (this.imgResponsive) ? 'img-responsive' : '',
1002 cfg.html = this.html || cfg.html;
1004 cfg.src = this.src || cfg.src;
1006 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1007 cfg.cls += ' img-' + this.border;
1024 a.target = this.target;
1030 return (this.href) ? a : cfg;
1033 initEvents: function() {
1036 this.el.on('click', this.onClick, this);
1040 onClick : function(e)
1042 Roo.log('img onclick');
1043 this.fireEvent('click', this, e);
1056 * @class Roo.bootstrap.Header
1057 * @extends Roo.bootstrap.Component
1058 * Bootstrap Header class
1059 * @cfg {String} html content of header
1060 * @cfg {Number} level (1|2|3|4|5|6) default 1
1063 * Create a new Header
1064 * @param {Object} config The config object
1068 Roo.bootstrap.Header = function(config){
1069 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1072 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1080 getAutoCreate : function(){
1083 tag: 'h' + (1 *this.level),
1084 html: this.html || 'fill in html'
1096 * Ext JS Library 1.1.1
1097 * Copyright(c) 2006-2007, Ext JS, LLC.
1099 * Originally Released Under LGPL - original licence link has changed is not relivant.
1102 * <script type="text/javascript">
1106 * @class Roo.bootstrap.MenuMgr
1107 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1110 Roo.bootstrap.MenuMgr = function(){
1111 var menus, active, groups = {}, attached = false, lastShow = new Date();
1113 // private - called when first menu is created
1116 active = new Roo.util.MixedCollection();
1117 Roo.get(document).addKeyListener(27, function(){
1118 if(active.length > 0){
1126 if(active && active.length > 0){
1127 var c = active.clone();
1137 if(active.length < 1){
1138 Roo.get(document).un("mouseup", onMouseDown);
1146 var last = active.last();
1147 lastShow = new Date();
1150 Roo.get(document).on("mouseup", onMouseDown);
1155 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1156 m.parentMenu.activeChild = m;
1157 }else if(last && last.isVisible()){
1158 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1163 function onBeforeHide(m){
1165 m.activeChild.hide();
1167 if(m.autoHideTimer){
1168 clearTimeout(m.autoHideTimer);
1169 delete m.autoHideTimer;
1174 function onBeforeShow(m){
1175 var pm = m.parentMenu;
1176 if(!pm && !m.allowOtherMenus){
1178 }else if(pm && pm.activeChild && active != m){
1179 pm.activeChild.hide();
1184 function onMouseDown(e){
1185 Roo.log("on MouseDown");
1186 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1194 function onBeforeCheck(mi, state){
1196 var g = groups[mi.group];
1197 for(var i = 0, l = g.length; i < l; i++){
1199 g[i].setChecked(false);
1208 * Hides all menus that are currently visible
1210 hideAll : function(){
1215 register : function(menu){
1219 menus[menu.id] = menu;
1220 menu.on("beforehide", onBeforeHide);
1221 menu.on("hide", onHide);
1222 menu.on("beforeshow", onBeforeShow);
1223 menu.on("show", onShow);
1225 if(g && menu.events["checkchange"]){
1229 groups[g].push(menu);
1230 menu.on("checkchange", onCheck);
1235 * Returns a {@link Roo.menu.Menu} object
1236 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1237 * be used to generate and return a new Menu instance.
1239 get : function(menu){
1240 if(typeof menu == "string"){ // menu id
1242 }else if(menu.events){ // menu instance
1245 /*else if(typeof menu.length == 'number'){ // array of menu items?
1246 return new Roo.bootstrap.Menu({items:menu});
1247 }else{ // otherwise, must be a config
1248 return new Roo.bootstrap.Menu(menu);
1255 unregister : function(menu){
1256 delete menus[menu.id];
1257 menu.un("beforehide", onBeforeHide);
1258 menu.un("hide", onHide);
1259 menu.un("beforeshow", onBeforeShow);
1260 menu.un("show", onShow);
1262 if(g && menu.events["checkchange"]){
1263 groups[g].remove(menu);
1264 menu.un("checkchange", onCheck);
1269 registerCheckable : function(menuItem){
1270 var g = menuItem.group;
1275 groups[g].push(menuItem);
1276 menuItem.on("beforecheckchange", onBeforeCheck);
1281 unregisterCheckable : function(menuItem){
1282 var g = menuItem.group;
1284 groups[g].remove(menuItem);
1285 menuItem.un("beforecheckchange", onBeforeCheck);
1297 * @class Roo.bootstrap.Menu
1298 * @extends Roo.bootstrap.Component
1299 * Bootstrap Menu class - container for MenuItems
1300 * @cfg {String} type type of menu
1304 * @param {Object} config The config object
1308 Roo.bootstrap.Menu = function(config){
1309 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1310 if (this.registerMenu) {
1311 Roo.bootstrap.MenuMgr.register(this);
1316 * Fires before this menu is displayed
1317 * @param {Roo.menu.Menu} this
1322 * Fires before this menu is hidden
1323 * @param {Roo.menu.Menu} this
1328 * Fires after this menu is displayed
1329 * @param {Roo.menu.Menu} this
1334 * Fires after this menu is hidden
1335 * @param {Roo.menu.Menu} this
1340 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1341 * @param {Roo.menu.Menu} this
1342 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1343 * @param {Roo.EventObject} e
1348 * Fires when the mouse is hovering over this menu
1349 * @param {Roo.menu.Menu} this
1350 * @param {Roo.EventObject} e
1351 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1356 * Fires when the mouse exits this menu
1357 * @param {Roo.menu.Menu} this
1358 * @param {Roo.EventObject} e
1359 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1364 * Fires when a menu item contained in this menu is clicked
1365 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1366 * @param {Roo.EventObject} e
1370 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1373 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1377 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1380 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1382 registerMenu : true,
1384 menuItems :false, // stores the menu items..
1390 getChildContainer : function() {
1394 getAutoCreate : function(){
1396 //if (['right'].indexOf(this.align)!==-1) {
1397 // cfg.cn[1].cls += ' pull-right'
1401 cls : 'dropdown-menu' ,
1402 style : 'z-index:1000'
1406 if (this.type === 'submenu') {
1407 cfg.cls = 'submenu active'
1412 initEvents : function() {
1414 // Roo.log("ADD event");
1415 // Roo.log(this.triggerEl.dom);
1416 this.triggerEl.on('click', this.onTriggerPress, this);
1417 this.triggerEl.addClass('dropdown-toggle');
1418 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1420 this.el.on("mouseover", this.onMouseOver, this);
1421 this.el.on("mouseout", this.onMouseOut, this);
1425 findTargetItem : function(e){
1426 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1430 //Roo.log(t); Roo.log(t.id);
1432 //Roo.log(this.menuitems);
1433 return this.menuitems.get(t.id);
1435 //return this.items.get(t.menuItemId);
1440 onClick : function(e){
1441 Roo.log("menu.onClick");
1442 var t = this.findTargetItem(e);
1448 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1449 if(t == this.activeItem && t.shouldDeactivate(e)){
1450 this.activeItem.deactivate();
1451 delete this.activeItem;
1455 this.setActiveItem(t, true);
1462 Roo.log('pass click event');
1466 this.fireEvent("click", this, t, e);
1470 onMouseOver : function(e){
1471 var t = this.findTargetItem(e);
1474 // if(t.canActivate && !t.disabled){
1475 // this.setActiveItem(t, true);
1479 this.fireEvent("mouseover", this, e, t);
1481 isVisible : function(){
1482 return !this.hidden;
1484 onMouseOut : function(e){
1485 var t = this.findTargetItem(e);
1488 // if(t == this.activeItem && t.shouldDeactivate(e)){
1489 // this.activeItem.deactivate();
1490 // delete this.activeItem;
1493 this.fireEvent("mouseout", this, e, t);
1498 * Displays this menu relative to another element
1499 * @param {String/HTMLElement/Roo.Element} element The element to align to
1500 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1501 * the element (defaults to this.defaultAlign)
1502 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1504 show : function(el, pos, parentMenu){
1505 this.parentMenu = parentMenu;
1509 this.fireEvent("beforeshow", this);
1510 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1513 * Displays this menu at a specific xy position
1514 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1515 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1517 showAt : function(xy, parentMenu, /* private: */_e){
1518 this.parentMenu = parentMenu;
1523 this.fireEvent("beforeshow", this);
1525 //xy = this.el.adjustForConstraints(xy);
1527 //this.el.setXY(xy);
1529 this.hideMenuItems();
1530 this.hidden = false;
1531 this.triggerEl.addClass('open');
1533 this.fireEvent("show", this);
1539 this.doFocus.defer(50, this);
1543 doFocus : function(){
1545 this.focusEl.focus();
1550 * Hides this menu and optionally all parent menus
1551 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1553 hide : function(deep){
1555 this.hideMenuItems();
1556 if(this.el && this.isVisible()){
1557 this.fireEvent("beforehide", this);
1558 if(this.activeItem){
1559 this.activeItem.deactivate();
1560 this.activeItem = null;
1562 this.triggerEl.removeClass('open');;
1564 this.fireEvent("hide", this);
1566 if(deep === true && this.parentMenu){
1567 this.parentMenu.hide(true);
1571 onTriggerPress : function(e)
1574 Roo.log('trigger press');
1575 //Roo.log(e.getTarget());
1576 // Roo.log(this.triggerEl.dom);
1577 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1580 if (this.isVisible()) {
1584 this.show(this.triggerEl, false, false);
1593 hideMenuItems : function()
1595 //$(backdrop).remove()
1596 Roo.select('.open',true).each(function(aa) {
1598 aa.removeClass('open');
1599 //var parent = getParent($(this))
1600 //var relatedTarget = { relatedTarget: this }
1602 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1603 //if (e.isDefaultPrevented()) return
1604 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1607 addxtypeChild : function (tree, cntr) {
1608 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1610 this.menuitems.add(comp);
1631 * @class Roo.bootstrap.MenuItem
1632 * @extends Roo.bootstrap.Component
1633 * Bootstrap MenuItem class
1634 * @cfg {String} html the menu label
1635 * @cfg {String} href the link
1636 * @cfg {Boolean} preventDefault (true | false) default true
1640 * Create a new MenuItem
1641 * @param {Object} config The config object
1645 Roo.bootstrap.MenuItem = function(config){
1646 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1651 * The raw click event for the entire grid.
1652 * @param {Roo.EventObject} e
1658 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1662 preventDefault: true,
1664 getAutoCreate : function(){
1667 cls: 'dropdown-menu-item',
1677 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1678 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1682 initEvents: function() {
1684 //this.el.select('a').on('click', this.onClick, this);
1687 onClick : function(e)
1689 Roo.log('item on click ');
1690 //if(this.preventDefault){
1691 // e.preventDefault();
1693 //this.parent().hideMenuItems();
1695 this.fireEvent('click', this, e);
1714 * @class Roo.bootstrap.MenuSeparator
1715 * @extends Roo.bootstrap.Component
1716 * Bootstrap MenuSeparator class
1719 * Create a new MenuItem
1720 * @param {Object} config The config object
1724 Roo.bootstrap.MenuSeparator = function(config){
1725 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1728 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1730 getAutoCreate : function(){
1745 <div class="modal fade">
1746 <div class="modal-dialog">
1747 <div class="modal-content">
1748 <div class="modal-header">
1749 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1750 <h4 class="modal-title">Modal title</h4>
1752 <div class="modal-body">
1753 <p>One fine body…</p>
1755 <div class="modal-footer">
1756 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1757 <button type="button" class="btn btn-primary">Save changes</button>
1759 </div><!-- /.modal-content -->
1760 </div><!-- /.modal-dialog -->
1761 </div><!-- /.modal -->
1771 * @class Roo.bootstrap.Modal
1772 * @extends Roo.bootstrap.Component
1773 * Bootstrap Modal class
1774 * @cfg {String} title Title of dialog
1775 * @cfg {Boolean} specificTitle (true|false) default false
1776 * @cfg {Array} buttons Array of buttons or standard button set..
1777 * @cfg {String} buttonPosition (left|right|center) default right
1780 * Create a new Modal Dialog
1781 * @param {Object} config The config object
1784 Roo.bootstrap.Modal = function(config){
1785 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1790 * The raw btnclick event for the button
1791 * @param {Roo.EventObject} e
1795 this.buttons = this.buttons || [];
1798 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1800 title : 'test dialog',
1807 specificTitle: false,
1809 buttonPosition: 'right',
1811 onRender : function(ct, position)
1813 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1816 var cfg = Roo.apply({}, this.getAutoCreate());
1819 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1821 //if (!cfg.name.length) {
1825 cfg.cls += ' ' + this.cls;
1828 cfg.style = this.style;
1830 this.el = Roo.get(document.body).createChild(cfg, position);
1832 //var type = this.el.dom.type;
1834 if(this.tabIndex !== undefined){
1835 this.el.dom.setAttribute('tabIndex', this.tabIndex);
1840 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1841 this.maskEl.enableDisplayMode("block");
1843 //this.el.addClass("x-dlg-modal");
1845 if (this.buttons.length) {
1846 Roo.each(this.buttons, function(bb) {
1847 b = Roo.apply({}, bb);
1848 b.xns = b.xns || Roo.bootstrap;
1849 b.xtype = b.xtype || 'Button';
1850 if (typeof(b.listeners) == 'undefined') {
1851 b.listeners = { click : this.onButtonClick.createDelegate(this) };
1854 var btn = Roo.factory(b);
1856 btn.onRender(this.el.select('.modal-footer div').first());
1860 // render the children.
1863 if(typeof(this.items) != 'undefined'){
1864 var items = this.items;
1867 for(var i =0;i < items.length;i++) {
1868 nitems.push(this.addxtype(Roo.apply({}, items[i])));
1872 this.items = nitems;
1874 this.body = this.el.select('.modal-body',true).first();
1875 this.close = this.el.select('.modal-header .close', true).first();
1876 this.footer = this.el.select('.modal-footer',true).first();
1878 //this.el.addClass([this.fieldClass, this.cls]);
1881 getAutoCreate : function(){
1886 html : this.html || ''
1891 cls : 'modal-title',
1895 if(this.specificTitle){
1901 style : 'display: none',
1904 cls: "modal-dialog",
1907 cls : "modal-content",
1910 cls : 'modal-header',
1922 cls : 'modal-footer',
1926 cls: 'btn-' + this.buttonPosition
1945 getChildContainer : function() {
1947 return this.el.select('.modal-body',true).first();
1950 getButtonContainer : function() {
1951 return this.el.select('.modal-footer div',true).first();
1954 initEvents : function()
1956 this.el.select('.modal-header .close').on('click', this.hide, this);
1958 // this.addxtype(this);
1962 if (!this.rendered) {
1966 this.el.addClass('on');
1967 this.el.removeClass('fade');
1968 this.el.setStyle('display', 'block');
1969 Roo.get(document.body).addClass("x-body-masked");
1970 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
1972 this.el.setStyle('zIndex', '10001');
1973 this.fireEvent('show', this);
1979 Roo.log('Modal hide?!');
1981 Roo.get(document.body).removeClass("x-body-masked");
1982 this.el.removeClass('on');
1983 this.el.addClass('fade');
1984 this.el.setStyle('display', 'none');
1985 this.fireEvent('hide', this);
1988 addButton : function(str, cb)
1992 var b = Roo.apply({}, { html : str } );
1993 b.xns = b.xns || Roo.bootstrap;
1994 b.xtype = b.xtype || 'Button';
1995 if (typeof(b.listeners) == 'undefined') {
1996 b.listeners = { click : cb.createDelegate(this) };
1999 var btn = Roo.factory(b);
2001 btn.onRender(this.el.select('.modal-footer div').first());
2007 setDefaultButton : function(btn)
2009 //this.el.select('.modal-footer').()
2011 resizeTo: function(w,h)
2015 setContentSize : function(w, h)
2019 onButtonClick: function(btn,e)
2022 this.fireEvent('btnclick', btn.name, e);
2024 setTitle: function(str) {
2025 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2031 Roo.apply(Roo.bootstrap.Modal, {
2033 * Button config that displays a single OK button
2042 * Button config that displays Yes and No buttons
2058 * Button config that displays OK and Cancel buttons
2073 * Button config that displays Yes, No and Cancel buttons
2095 * messagebox - can be used as a replace
2099 * @class Roo.MessageBox
2100 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2104 Roo.Msg.alert('Status', 'Changes saved successfully.');
2106 // Prompt for user data:
2107 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2109 // process text value...
2113 // Show a dialog using config options:
2115 title:'Save Changes?',
2116 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2117 buttons: Roo.Msg.YESNOCANCEL,
2124 Roo.bootstrap.MessageBox = function(){
2125 var dlg, opt, mask, waitTimer;
2126 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2127 var buttons, activeTextEl, bwidth;
2131 var handleButton = function(button){
2133 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2137 var handleHide = function(){
2139 dlg.el.removeClass(opt.cls);
2142 // Roo.TaskMgr.stop(waitTimer);
2143 // waitTimer = null;
2148 var updateButtons = function(b){
2151 buttons["ok"].hide();
2152 buttons["cancel"].hide();
2153 buttons["yes"].hide();
2154 buttons["no"].hide();
2155 //dlg.footer.dom.style.display = 'none';
2158 dlg.footer.dom.style.display = '';
2159 for(var k in buttons){
2160 if(typeof buttons[k] != "function"){
2163 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2164 width += buttons[k].el.getWidth()+15;
2174 var handleEsc = function(d, k, e){
2175 if(opt && opt.closable !== false){
2185 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2186 * @return {Roo.BasicDialog} The BasicDialog element
2188 getDialog : function(){
2190 dlg = new Roo.bootstrap.Modal( {
2193 //constraintoviewport:false,
2195 //collapsible : false,
2200 //buttonAlign:"center",
2201 closeClick : function(){
2202 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2205 handleButton("cancel");
2210 dlg.on("hide", handleHide);
2212 //dlg.addKeyListener(27, handleEsc);
2214 this.buttons = buttons;
2215 var bt = this.buttonText;
2216 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2217 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2218 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2219 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2221 bodyEl = dlg.body.createChild({
2223 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2224 '<textarea class="roo-mb-textarea"></textarea>' +
2225 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2227 msgEl = bodyEl.dom.firstChild;
2228 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2229 textboxEl.enableDisplayMode();
2230 textboxEl.addKeyListener([10,13], function(){
2231 if(dlg.isVisible() && opt && opt.buttons){
2234 }else if(opt.buttons.yes){
2235 handleButton("yes");
2239 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2240 textareaEl.enableDisplayMode();
2241 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2242 progressEl.enableDisplayMode();
2243 var pf = progressEl.dom.firstChild;
2245 pp = Roo.get(pf.firstChild);
2246 pp.setHeight(pf.offsetHeight);
2254 * Updates the message box body text
2255 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2256 * the XHTML-compliant non-breaking space character '&#160;')
2257 * @return {Roo.MessageBox} This message box
2259 updateText : function(text){
2260 if(!dlg.isVisible() && !opt.width){
2261 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2263 msgEl.innerHTML = text || ' ';
2265 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2266 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2268 Math.min(opt.width || cw , this.maxWidth),
2269 Math.max(opt.minWidth || this.minWidth, bwidth)
2272 activeTextEl.setWidth(w);
2274 if(dlg.isVisible()){
2275 dlg.fixedcenter = false;
2277 // to big, make it scroll. = But as usual stupid IE does not support
2280 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2281 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2282 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2284 bodyEl.dom.style.height = '';
2285 bodyEl.dom.style.overflowY = '';
2288 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2290 bodyEl.dom.style.overflowX = '';
2293 dlg.setContentSize(w, bodyEl.getHeight());
2294 if(dlg.isVisible()){
2295 dlg.fixedcenter = true;
2301 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2302 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2303 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2304 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2305 * @return {Roo.MessageBox} This message box
2307 updateProgress : function(value, text){
2309 this.updateText(text);
2311 if (pp) { // weird bug on my firefox - for some reason this is not defined
2312 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2318 * Returns true if the message box is currently displayed
2319 * @return {Boolean} True if the message box is visible, else false
2321 isVisible : function(){
2322 return dlg && dlg.isVisible();
2326 * Hides the message box if it is displayed
2329 if(this.isVisible()){
2335 * Displays a new message box, or reinitializes an existing message box, based on the config options
2336 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2337 * The following config object properties are supported:
2339 Property Type Description
2340 ---------- --------------- ------------------------------------------------------------------------------------
2341 animEl String/Element An id or Element from which the message box should animate as it opens and
2342 closes (defaults to undefined)
2343 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2344 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2345 closable Boolean False to hide the top-right close button (defaults to true). Note that
2346 progress and wait dialogs will ignore this property and always hide the
2347 close button as they can only be closed programmatically.
2348 cls String A custom CSS class to apply to the message box element
2349 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2350 displayed (defaults to 75)
2351 fn Function A callback function to execute after closing the dialog. The arguments to the
2352 function will be btn (the name of the button that was clicked, if applicable,
2353 e.g. "ok"), and text (the value of the active text field, if applicable).
2354 Progress and wait dialogs will ignore this option since they do not respond to
2355 user actions and can only be closed programmatically, so any required function
2356 should be called by the same code after it closes the dialog.
2357 icon String A CSS class that provides a background image to be used as an icon for
2358 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2359 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2360 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2361 modal Boolean False to allow user interaction with the page while the message box is
2362 displayed (defaults to true)
2363 msg String A string that will replace the existing message box body text (defaults
2364 to the XHTML-compliant non-breaking space character ' ')
2365 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2366 progress Boolean True to display a progress bar (defaults to false)
2367 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2368 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2369 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2370 title String The title text
2371 value String The string value to set into the active textbox element if displayed
2372 wait Boolean True to display a progress bar (defaults to false)
2373 width Number The width of the dialog in pixels
2380 msg: 'Please enter your address:',
2382 buttons: Roo.MessageBox.OKCANCEL,
2385 animEl: 'addAddressBtn'
2388 * @param {Object} config Configuration options
2389 * @return {Roo.MessageBox} This message box
2391 show : function(options)
2394 // this causes nightmares if you show one dialog after another
2395 // especially on callbacks..
2397 if(this.isVisible()){
2400 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2401 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2402 Roo.log("New Dialog Message:" + options.msg )
2403 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2404 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2407 var d = this.getDialog();
2409 d.setTitle(opt.title || " ");
2410 d.close.setDisplayed(opt.closable !== false);
2411 activeTextEl = textboxEl;
2412 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2417 textareaEl.setHeight(typeof opt.multiline == "number" ?
2418 opt.multiline : this.defaultTextHeight);
2419 activeTextEl = textareaEl;
2428 progressEl.setDisplayed(opt.progress === true);
2429 this.updateProgress(0);
2430 activeTextEl.dom.value = opt.value || "";
2432 dlg.setDefaultButton(activeTextEl);
2434 var bs = opt.buttons;
2438 }else if(bs && bs.yes){
2439 db = buttons["yes"];
2441 dlg.setDefaultButton(db);
2443 bwidth = updateButtons(opt.buttons);
2444 this.updateText(opt.msg);
2446 d.el.addClass(opt.cls);
2448 d.proxyDrag = opt.proxyDrag === true;
2449 d.modal = opt.modal !== false;
2450 d.mask = opt.modal !== false ? mask : false;
2452 // force it to the end of the z-index stack so it gets a cursor in FF
2453 document.body.appendChild(dlg.el.dom);
2454 d.animateTarget = null;
2455 d.show(options.animEl);
2461 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2462 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2463 * and closing the message box when the process is complete.
2464 * @param {String} title The title bar text
2465 * @param {String} msg The message box body text
2466 * @return {Roo.MessageBox} This message box
2468 progress : function(title, msg){
2475 minWidth: this.minProgressWidth,
2482 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2483 * If a callback function is passed it will be called after the user clicks the button, and the
2484 * id of the button that was clicked will be passed as the only parameter to the callback
2485 * (could also be the top-right close button).
2486 * @param {String} title The title bar text
2487 * @param {String} msg The message box body text
2488 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2489 * @param {Object} scope (optional) The scope of the callback function
2490 * @return {Roo.MessageBox} This message box
2492 alert : function(title, msg, fn, scope){
2505 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2506 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2507 * You are responsible for closing the message box when the process is complete.
2508 * @param {String} msg The message box body text
2509 * @param {String} title (optional) The title bar text
2510 * @return {Roo.MessageBox} This message box
2512 wait : function(msg, title){
2523 waitTimer = Roo.TaskMgr.start({
2525 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2533 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2534 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2535 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2536 * @param {String} title The title bar text
2537 * @param {String} msg The message box body text
2538 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2539 * @param {Object} scope (optional) The scope of the callback function
2540 * @return {Roo.MessageBox} This message box
2542 confirm : function(title, msg, fn, scope){
2546 buttons: this.YESNO,
2555 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2556 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2557 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2558 * (could also be the top-right close button) and the text that was entered will be passed as the two
2559 * parameters to the callback.
2560 * @param {String} title The title bar text
2561 * @param {String} msg The message box body text
2562 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2563 * @param {Object} scope (optional) The scope of the callback function
2564 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2565 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2566 * @return {Roo.MessageBox} This message box
2568 prompt : function(title, msg, fn, scope, multiline){
2572 buttons: this.OKCANCEL,
2577 multiline: multiline,
2584 * Button config that displays a single OK button
2589 * Button config that displays Yes and No buttons
2592 YESNO : {yes:true, no:true},
2594 * Button config that displays OK and Cancel buttons
2597 OKCANCEL : {ok:true, cancel:true},
2599 * Button config that displays Yes, No and Cancel buttons
2602 YESNOCANCEL : {yes:true, no:true, cancel:true},
2605 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2608 defaultTextHeight : 75,
2610 * The maximum width in pixels of the message box (defaults to 600)
2615 * The minimum width in pixels of the message box (defaults to 100)
2620 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2621 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2624 minProgressWidth : 250,
2626 * An object containing the default button text strings that can be overriden for localized language support.
2627 * Supported properties are: ok, cancel, yes and no.
2628 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2641 * Shorthand for {@link Roo.MessageBox}
2643 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2644 Roo.Msg = Roo.Msg || Roo.MessageBox;
2653 * @class Roo.bootstrap.Navbar
2654 * @extends Roo.bootstrap.Component
2655 * Bootstrap Navbar class
2658 * Create a new Navbar
2659 * @param {Object} config The config object
2663 Roo.bootstrap.Navbar = function(config){
2664 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2668 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2677 getAutoCreate : function(){
2680 throw { message : "nav bar is now a abstract base class - use SimpleBar / HeaderBar / SideBar etc..."};
2684 initEvents :function ()
2686 //Roo.log(this.el.select('.navbar-toggle',true));
2687 this.el.select('.navbar-toggle',true).on('click', function() {
2688 // Roo.log('click');
2689 this.el.select('.navbar-collapse',true).toggleClass('in');
2697 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2699 var size = this.el.getSize();
2700 this.maskEl.setSize(size.width, size.height);
2701 this.maskEl.enableDisplayMode("block");
2710 getChildContainer : function()
2712 if (this.el.select('.collapse').getCount()) {
2713 return this.el.select('.collapse',true).first();
2745 * @class Roo.bootstrap.NavSimplebar
2746 * @extends Roo.bootstrap.Navbar
2747 * Bootstrap Sidebar class
2749 * @cfg {Boolean} inverse is inverted color
2751 * @cfg {String} type (nav | pills | tabs)
2752 * @cfg {Boolean} arrangement stacked | justified
2753 * @cfg {String} align (left | right) alignment
2755 * @cfg {Boolean} main (true|false) main nav bar? default false
2756 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
2758 * @cfg {String} tag (header|footer|nav|div) default is nav
2764 * Create a new Sidebar
2765 * @param {Object} config The config object
2769 Roo.bootstrap.NavSimplebar = function(config){
2770 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
2773 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
2789 getAutoCreate : function(){
2793 tag : this.tag || 'div',
2806 this.type = this.type || 'nav';
2807 if (['tabs','pills'].indexOf(this.type)!==-1) {
2808 cfg.cn[0].cls += ' nav-' + this.type
2812 if (this.type!=='nav') {
2813 Roo.log('nav type must be nav/tabs/pills')
2815 cfg.cn[0].cls += ' navbar-nav'
2821 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
2822 cfg.cn[0].cls += ' nav-' + this.arrangement;
2826 if (this.align === 'right') {
2827 cfg.cn[0].cls += ' navbar-right';
2831 cfg.cls += ' navbar-inverse';
2858 * @class Roo.bootstrap.NavHeaderbar
2859 * @extends Roo.bootstrap.NavSimplebar
2860 * Bootstrap Sidebar class
2862 * @cfg {String} brand what is brand
2863 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
2864 * @cfg {String} brand_href href of the brand
2867 * Create a new Sidebar
2868 * @param {Object} config The config object
2872 Roo.bootstrap.NavHeaderbar = function(config){
2873 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
2876 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
2883 getAutoCreate : function(){
2888 tag: this.nav || 'nav',
2894 cls: 'navbar-header',
2899 cls: 'navbar-toggle',
2900 'data-toggle': 'collapse',
2905 html: 'Toggle navigation'
2925 cls: 'collapse navbar-collapse'
2930 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
2932 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
2933 cfg.cls += ' navbar-' + this.position;
2935 // tag can override this..
2937 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
2940 if (this.brand !== '') {
2943 href: this.brand_href ? this.brand_href : '#',
2944 cls: 'navbar-brand',
2952 cfg.cls += ' main-nav';
2977 * @class Roo.bootstrap.NavSidebar
2978 * @extends Roo.bootstrap.Navbar
2979 * Bootstrap Sidebar class
2982 * Create a new Sidebar
2983 * @param {Object} config The config object
2987 Roo.bootstrap.NavSidebar = function(config){
2988 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
2991 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
2994 getAutoCreate : function(){
3021 * @class Roo.bootstrap.NavGroup
3022 * @extends Roo.bootstrap.Component
3023 * Bootstrap NavGroup class
3024 * @cfg {String} align left | right
3025 * @cfg {Boolean} inverse false | true
3026 * @cfg {String} type (nav|pills|tab) default nav
3027 * @cfg {String} navId - reference Id for navbar.
3031 * Create a new nav group
3032 * @param {Object} config The config object
3035 Roo.bootstrap.NavGroup = function(config){
3036 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3038 Roo.bootstrap.NavGroup.register(this);
3042 * Fires when the active item changes
3043 * @param {Roo.bootstrap.NavGroup} this
3044 * @param {Roo.bootstrap.Navbar.Item} item The item selected
3045 * @param {Roo.bootstrap.Navbar.Item} item The previously selected item
3052 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3063 getAutoCreate : function()
3065 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3072 if (['tabs','pills'].indexOf(this.type)!==-1) {
3073 cfg.cls += ' nav-' + this.type
3075 if (this.type!=='nav') {
3076 Roo.log('nav type must be nav/tabs/pills')
3078 cfg.cls += ' navbar-nav'
3081 if (this.parent().sidebar === true) {
3084 cls: 'dashboard-menu'
3090 if (this.form === true) {
3096 if (this.align === 'right') {
3097 cfg.cls += ' navbar-right';
3099 cfg.cls += ' navbar-left';
3103 if (this.align === 'right') {
3104 cfg.cls += ' navbar-right';
3108 cfg.cls += ' navbar-inverse';
3116 setActiveItem : function(item)
3119 Roo.each(this.navItems, function(v){
3124 v.setActive(false, true);
3131 item.setActive(true, true);
3132 this.fireEvent('changed', this, item, prev);
3138 register : function(item)
3140 this.navItems.push( item);
3141 item.navId = this.navId;
3144 getNavItem: function(tabId)
3147 Roo.each(this.navItems, function(e) {
3148 if (e.tabId == tabId) {
3160 Roo.apply(Roo.bootstrap.NavGroup, {
3164 register : function(navgrp)
3166 this.groups[navgrp.navId] = navgrp;
3169 get: function(navId) {
3170 return this.groups[navId];
3185 * @class Roo.bootstrap.Navbar.Item
3186 * @extends Roo.bootstrap.Component
3187 * Bootstrap Navbar.Button class
3188 * @cfg {String} href link to
3189 * @cfg {String} html content of button
3190 * @cfg {String} badge text inside badge
3191 * @cfg {String} glyphicon name of glyphicon
3192 * @cfg {String} icon name of font awesome icon
3193 * @cfg {Boolean} active Is item active
3194 * @cfg {Boolean} preventDefault (true | false) default false
3195 * @cfg {String} tabId the tab that this item activates.
3198 * Create a new Navbar Button
3199 * @param {Object} config The config object
3201 Roo.bootstrap.Navbar.Item = function(config){
3202 Roo.bootstrap.Navbar.Item.superclass.constructor.call(this, config);
3207 * The raw click event for the entire grid.
3208 * @param {Roo.EventObject} e
3213 * Fires when the active item active state changes
3214 * @param {Roo.bootstrap.Navbar.Item} this
3215 * @param {boolean} state the new state
3223 Roo.extend(Roo.bootstrap.Navbar.Item, Roo.bootstrap.Component, {
3231 preventDefault : false,
3234 getAutoCreate : function(){
3236 var cfg = Roo.apply({}, Roo.bootstrap.Navbar.Item.superclass.getAutoCreate.call(this));
3238 if (this.parent().parent().sidebar === true) {
3251 cfg.cn[0].html = this.html;
3255 this.cls += ' active';
3259 cfg.cn[0].cls += ' dropdown-toggle';
3260 cfg.cn[0].html = (cfg.cn[0].html || this.html) + '<span class="glyphicon glyphicon-chevron-down"></span>';
3264 cfg.cn[0].tag = 'a',
3265 cfg.cn[0].href = this.href;
3268 if (this.glyphicon) {
3269 cfg.cn[0].html = '<i class="glyphicon glyphicon-'+this.glyphicon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
3273 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
3285 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3295 if (this.glyphicon) {
3296 if(cfg.html){cfg.html = ' ' + this.html};
3300 cls: 'glyphicon glyphicon-' + this.glyphicon
3305 cfg.cn[0].html = this.html || cfg.cn[0].html ;
3310 cfg.cn[0].html += " <span class='caret'></span>";
3311 //}else if (!this.href) {
3312 // cfg.cn[0].tag='p';
3313 // cfg.cn[0].cls='navbar-text';
3316 cfg.cn[0].href=this.href||'#';
3317 cfg.cn[0].html=this.html;
3320 if (this.badge !== '') {
3323 cfg.cn[0].html + ' ',
3334 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
3339 initEvents: function() {
3340 // Roo.log('init events?');
3341 // Roo.log(this.el.dom);
3342 this.el.select('a',true).on('click', this.onClick, this);
3343 // at this point parent should be available..
3344 this.parent().register(this);
3347 onClick : function(e)
3349 if(this.preventDefault){
3353 if(this.fireEvent('click', this, e) === false){
3357 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3358 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3359 this.parent().setActiveItem(this);
3367 isActive: function () {
3370 setActive : function(state, fire)
3372 this.active = state;
3374 this.el.removeClass('active');
3375 } else if (!this.el.hasClass('active')) {
3376 this.el.addClass('active');
3379 this.fireEvent('changed', this, state);
3384 // this should not be here...
3397 * @class Roo.bootstrap.Row
3398 * @extends Roo.bootstrap.Component
3399 * Bootstrap Row class (contains columns...)
3403 * @param {Object} config The config object
3406 Roo.bootstrap.Row = function(config){
3407 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3410 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3412 getAutoCreate : function(){
3431 * @class Roo.bootstrap.Element
3432 * @extends Roo.bootstrap.Component
3433 * Bootstrap Element class
3434 * @cfg {String} html contents of the element
3435 * @cfg {String} tag tag of the element
3436 * @cfg {String} cls class of the element
3439 * Create a new Element
3440 * @param {Object} config The config object
3443 Roo.bootstrap.Element = function(config){
3444 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3447 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3454 getAutoCreate : function(){
3479 * @class Roo.bootstrap.Pagination
3480 * @extends Roo.bootstrap.Component
3481 * Bootstrap Pagination class
3482 * @cfg {String} size xs | sm | md | lg
3483 * @cfg {Boolean} inverse false | true
3486 * Create a new Pagination
3487 * @param {Object} config The config object
3490 Roo.bootstrap.Pagination = function(config){
3491 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3494 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3500 getAutoCreate : function(){
3506 cfg.cls += ' inverse';
3512 cfg.cls += " " + this.cls;
3530 * @class Roo.bootstrap.PaginationItem
3531 * @extends Roo.bootstrap.Component
3532 * Bootstrap PaginationItem class
3533 * @cfg {String} html text
3534 * @cfg {String} href the link
3535 * @cfg {Boolean} preventDefault (true | false) default true
3536 * @cfg {Boolean} active (true | false) default false
3540 * Create a new PaginationItem
3541 * @param {Object} config The config object
3545 Roo.bootstrap.PaginationItem = function(config){
3546 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3551 * The raw click event for the entire grid.
3552 * @param {Roo.EventObject} e
3558 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
3562 preventDefault: true,
3566 getAutoCreate : function(){
3572 href : this.href ? this.href : '#',
3573 html : this.html ? this.html : ''
3583 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
3589 initEvents: function() {
3591 this.el.on('click', this.onClick, this);
3594 onClick : function(e)
3596 Roo.log('PaginationItem on click ');
3597 if(this.preventDefault){
3601 this.fireEvent('click', this, e);
3617 * @class Roo.bootstrap.Slider
3618 * @extends Roo.bootstrap.Component
3619 * Bootstrap Slider class
3622 * Create a new Slider
3623 * @param {Object} config The config object
3626 Roo.bootstrap.Slider = function(config){
3627 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
3630 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
3632 getAutoCreate : function(){
3636 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
3640 cls: 'ui-slider-handle ui-state-default ui-corner-all'
3658 * @class Roo.bootstrap.Table
3659 * @extends Roo.bootstrap.Component
3660 * Bootstrap Table class
3661 * @cfg {String} cls table class
3662 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
3663 * @cfg {String} bgcolor Specifies the background color for a table
3664 * @cfg {Number} border Specifies whether the table cells should have borders or not
3665 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
3666 * @cfg {Number} cellspacing Specifies the space between cells
3667 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
3668 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
3669 * @cfg {String} sortable Specifies that the table should be sortable
3670 * @cfg {String} summary Specifies a summary of the content of a table
3671 * @cfg {Number} width Specifies the width of a table
3673 * @cfg {boolean} striped Should the rows be alternative striped
3674 * @cfg {boolean} bordered Add borders to the table
3675 * @cfg {boolean} hover Add hover highlighting
3676 * @cfg {boolean} condensed Format condensed
3677 * @cfg {boolean} responsive Format condensed
3683 * Create a new Table
3684 * @param {Object} config The config object
3687 Roo.bootstrap.Table = function(config){
3688 Roo.bootstrap.Table.superclass.constructor.call(this, config);
3691 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
3692 this.sm = this.selModel;
3693 this.sm.xmodule = this.xmodule || false;
3695 if (this.cm && typeof(this.cm.config) == 'undefined') {
3696 this.colModel = new Roo.bootstrap.Table.ColumnModel(this.cm);
3697 this.cm = this.colModel;
3698 this.cm.xmodule = this.xmodule || false;
3701 this.store= Roo.factory(this.store, Roo.data);
3702 this.ds = this.store;
3703 this.ds.xmodule = this.xmodule || false;
3708 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
3730 getAutoCreate : function(){
3731 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
3740 cfg.cls += ' table-striped';
3743 cfg.cls += ' table-hover';
3745 if (this.bordered) {
3746 cfg.cls += ' table-bordered';
3748 if (this.condensed) {
3749 cfg.cls += ' table-condensed';
3751 if (this.responsive) {
3752 cfg.cls += ' table-responsive';
3759 cfg.cls+= ' ' +this.cls;
3762 // this lot should be simplifed...
3765 cfg.align=this.align;
3768 cfg.bgcolor=this.bgcolor;
3771 cfg.border=this.border;
3773 if (this.cellpadding) {
3774 cfg.cellpadding=this.cellpadding;
3776 if (this.cellspacing) {
3777 cfg.cellspacing=this.cellspacing;
3780 cfg.frame=this.frame;
3783 cfg.rules=this.rules;
3785 if (this.sortable) {
3786 cfg.sortable=this.sortable;
3789 cfg.summary=this.summary;
3792 cfg.width=this.width;
3795 if(this.store || this.cm){
3796 cfg.cn.push(this.renderHeader());
3797 cfg.cn.push(this.renderBody());
3798 cfg.cn.push(this.renderFooter());
3800 cfg.cls+= ' TableGrid';
3806 // initTableGrid : function()
3815 // var cm = this.cm;
3817 // for(var i = 0, len = cm.getColumnCount(); i < len; i++){
3820 // html: cm.getColumnHeader(i)
3824 // cfg.push(header);
3831 initEvents : function()
3833 if(!this.store || !this.cm){
3837 Roo.log('initEvents with ds!!!!');
3841 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
3842 e.on('click', _this.sort, _this);
3844 // this.maskEl = Roo.DomHelper.append(this.el.select('.TableGrid', true).first(), {tag: "div", cls:"x-dlg-mask"}, true);
3845 // this.maskEl.enableDisplayMode("block");
3846 // this.maskEl.show();
3848 this.store.on('load', this.onLoad, this);
3849 this.store.on('beforeload', this.onBeforeLoad, this);
3857 sort : function(e,el)
3859 var col = Roo.get(el)
3861 if(!col.hasClass('sortable')){
3865 var sort = col.attr('sort');
3868 if(col.hasClass('glyphicon-arrow-up')){
3872 this.store.sortInfo = {field : sort, direction : dir};
3877 renderHeader : function()
3886 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
3888 var config = cm.config[i];
3892 html: cm.getColumnHeader(i)
3895 if(typeof(config.dataIndex) != 'undefined'){
3896 c.sort = config.dataIndex;
3899 if(typeof(config.sortable) != 'undefined' && config.sortable){
3903 if(typeof(config.width) != 'undefined'){
3904 c.style = 'width:' + config.width + 'px';
3913 renderBody : function()
3923 renderFooter : function()
3935 Roo.log('ds onload');
3940 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
3941 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
3943 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
3944 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
3947 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
3948 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
3952 var tbody = this.el.select('tbody', true).first();
3956 if(this.store.getCount() > 0){
3957 this.store.data.each(function(d){
3963 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
3964 var renderer = cm.getRenderer(i);
3965 var config = cm.config[i];
3969 if(typeof(renderer) !== 'undefined'){
3970 value = renderer(d.data[cm.getDataIndex(i)], false, d);
3973 if(typeof(value) === 'object'){
3983 html: (typeof(value) === 'object') ? '' : value
3986 if(typeof(config.width) != 'undefined'){
3987 td.style = 'width:' + config.width + 'px';
3994 tbody.createChild(row);
4002 Roo.each(renders, function(r){
4003 _this.renderColumn(r);
4007 // if(this.loadMask){
4008 // this.maskEl.hide();
4012 onBeforeLoad : function()
4014 Roo.log('ds onBeforeLoad');
4018 // if(this.loadMask){
4019 // this.maskEl.show();
4025 this.el.select('tbody', true).first().dom.innerHTML = '';
4028 getSelectionModel : function(){
4030 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
4032 return this.selModel;
4035 renderColumn : function(r)
4038 r.cfg.render(Roo.get(r.id));
4041 Roo.each(r.cfg.cn, function(c){
4046 _this.renderColumn(child);
4063 * @class Roo.bootstrap.TableCell
4064 * @extends Roo.bootstrap.Component
4065 * Bootstrap TableCell class
4066 * @cfg {String} html cell contain text
4067 * @cfg {String} cls cell class
4068 * @cfg {String} tag cell tag (td|th) default td
4069 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
4070 * @cfg {String} align Aligns the content in a cell
4071 * @cfg {String} axis Categorizes cells
4072 * @cfg {String} bgcolor Specifies the background color of a cell
4073 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
4074 * @cfg {Number} colspan Specifies the number of columns a cell should span
4075 * @cfg {String} headers Specifies one or more header cells a cell is related to
4076 * @cfg {Number} height Sets the height of a cell
4077 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
4078 * @cfg {Number} rowspan Sets the number of rows a cell should span
4079 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
4080 * @cfg {String} valign Vertical aligns the content in a cell
4081 * @cfg {Number} width Specifies the width of a cell
4084 * Create a new TableCell
4085 * @param {Object} config The config object
4088 Roo.bootstrap.TableCell = function(config){
4089 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
4092 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
4112 getAutoCreate : function(){
4113 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
4133 cfg.align=this.align
4139 cfg.bgcolor=this.bgcolor
4142 cfg.charoff=this.charoff
4145 cfg.colspan=this.colspan
4148 cfg.headers=this.headers
4151 cfg.height=this.height
4154 cfg.nowrap=this.nowrap
4157 cfg.rowspan=this.rowspan
4160 cfg.scope=this.scope
4163 cfg.valign=this.valign
4166 cfg.width=this.width
4185 * @class Roo.bootstrap.TableRow
4186 * @extends Roo.bootstrap.Component
4187 * Bootstrap TableRow class
4188 * @cfg {String} cls row class
4189 * @cfg {String} align Aligns the content in a table row
4190 * @cfg {String} bgcolor Specifies a background color for a table row
4191 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
4192 * @cfg {String} valign Vertical aligns the content in a table row
4195 * Create a new TableRow
4196 * @param {Object} config The config object
4199 Roo.bootstrap.TableRow = function(config){
4200 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
4203 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
4211 getAutoCreate : function(){
4212 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
4222 cfg.align = this.align;
4225 cfg.bgcolor = this.bgcolor;
4228 cfg.charoff = this.charoff;
4231 cfg.valign = this.valign;
4249 * @class Roo.bootstrap.TableBody
4250 * @extends Roo.bootstrap.Component
4251 * Bootstrap TableBody class
4252 * @cfg {String} cls element class
4253 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
4254 * @cfg {String} align Aligns the content inside the element
4255 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
4256 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
4259 * Create a new TableBody
4260 * @param {Object} config The config object
4263 Roo.bootstrap.TableBody = function(config){
4264 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
4267 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
4275 getAutoCreate : function(){
4276 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
4290 cfg.align = this.align;
4293 cfg.charoff = this.charoff;
4296 cfg.valign = this.valign;
4303 // initEvents : function()
4310 // this.store = Roo.factory(this.store, Roo.data);
4311 // this.store.on('load', this.onLoad, this);
4313 // this.store.load();
4317 // onLoad: function ()
4319 // this.fireEvent('load', this);
4329 * Ext JS Library 1.1.1
4330 * Copyright(c) 2006-2007, Ext JS, LLC.
4332 * Originally Released Under LGPL - original licence link has changed is not relivant.
4335 * <script type="text/javascript">
4338 // as we use this in bootstrap.
4339 Roo.namespace('Roo.form');
4341 * @class Roo.form.Action
4342 * Internal Class used to handle form actions
4344 * @param {Roo.form.BasicForm} el The form element or its id
4345 * @param {Object} config Configuration options
4350 // define the action interface
4351 Roo.form.Action = function(form, options){
4353 this.options = options || {};
4356 * Client Validation Failed
4359 Roo.form.Action.CLIENT_INVALID = 'client';
4361 * Server Validation Failed
4364 Roo.form.Action.SERVER_INVALID = 'server';
4366 * Connect to Server Failed
4369 Roo.form.Action.CONNECT_FAILURE = 'connect';
4371 * Reading Data from Server Failed
4374 Roo.form.Action.LOAD_FAILURE = 'load';
4376 Roo.form.Action.prototype = {
4378 failureType : undefined,
4379 response : undefined,
4383 run : function(options){
4388 success : function(response){
4393 handleResponse : function(response){
4397 // default connection failure
4398 failure : function(response){
4400 this.response = response;
4401 this.failureType = Roo.form.Action.CONNECT_FAILURE;
4402 this.form.afterAction(this, false);
4405 processResponse : function(response){
4406 this.response = response;
4407 if(!response.responseText){
4410 this.result = this.handleResponse(response);
4414 // utility functions used internally
4415 getUrl : function(appendParams){
4416 var url = this.options.url || this.form.url || this.form.el.dom.action;
4418 var p = this.getParams();
4420 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
4426 getMethod : function(){
4427 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
4430 getParams : function(){
4431 var bp = this.form.baseParams;
4432 var p = this.options.params;
4434 if(typeof p == "object"){
4435 p = Roo.urlEncode(Roo.applyIf(p, bp));
4436 }else if(typeof p == 'string' && bp){
4437 p += '&' + Roo.urlEncode(bp);
4440 p = Roo.urlEncode(bp);
4445 createCallback : function(){
4447 success: this.success,
4448 failure: this.failure,
4450 timeout: (this.form.timeout*1000),
4451 upload: this.form.fileUpload ? this.success : undefined
4456 Roo.form.Action.Submit = function(form, options){
4457 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
4460 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
4463 haveProgress : false,
4464 uploadComplete : false,
4466 // uploadProgress indicator.
4467 uploadProgress : function()
4469 if (!this.form.progressUrl) {
4473 if (!this.haveProgress) {
4474 Roo.MessageBox.progress("Uploading", "Uploading");
4476 if (this.uploadComplete) {
4477 Roo.MessageBox.hide();
4481 this.haveProgress = true;
4483 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
4485 var c = new Roo.data.Connection();
4487 url : this.form.progressUrl,
4492 success : function(req){
4493 //console.log(data);
4497 rdata = Roo.decode(req.responseText)
4499 Roo.log("Invalid data from server..");
4503 if (!rdata || !rdata.success) {
4505 Roo.MessageBox.alert(Roo.encode(rdata));
4508 var data = rdata.data;
4510 if (this.uploadComplete) {
4511 Roo.MessageBox.hide();
4516 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
4517 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
4520 this.uploadProgress.defer(2000,this);
4523 failure: function(data) {
4524 Roo.log('progress url failed ');
4535 // run get Values on the form, so it syncs any secondary forms.
4536 this.form.getValues();
4538 var o = this.options;
4539 var method = this.getMethod();
4540 var isPost = method == 'POST';
4541 if(o.clientValidation === false || this.form.isValid()){
4543 if (this.form.progressUrl) {
4544 this.form.findField('UPLOAD_IDENTIFIER').setValue(
4545 (new Date() * 1) + '' + Math.random());
4550 Roo.Ajax.request(Roo.apply(this.createCallback(), {
4551 form:this.form.el.dom,
4552 url:this.getUrl(!isPost),
4554 params:isPost ? this.getParams() : null,
4555 isUpload: this.form.fileUpload
4558 this.uploadProgress();
4560 }else if (o.clientValidation !== false){ // client validation failed
4561 this.failureType = Roo.form.Action.CLIENT_INVALID;
4562 this.form.afterAction(this, false);
4566 success : function(response)
4568 this.uploadComplete= true;
4569 if (this.haveProgress) {
4570 Roo.MessageBox.hide();
4574 var result = this.processResponse(response);
4575 if(result === true || result.success){
4576 this.form.afterAction(this, true);
4580 this.form.markInvalid(result.errors);
4581 this.failureType = Roo.form.Action.SERVER_INVALID;
4583 this.form.afterAction(this, false);
4585 failure : function(response)
4587 this.uploadComplete= true;
4588 if (this.haveProgress) {
4589 Roo.MessageBox.hide();
4592 this.response = response;
4593 this.failureType = Roo.form.Action.CONNECT_FAILURE;
4594 this.form.afterAction(this, false);
4597 handleResponse : function(response){
4598 if(this.form.errorReader){
4599 var rs = this.form.errorReader.read(response);
4602 for(var i = 0, len = rs.records.length; i < len; i++) {
4603 var r = rs.records[i];
4607 if(errors.length < 1){
4611 success : rs.success,
4617 ret = Roo.decode(response.responseText);
4621 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
4631 Roo.form.Action.Load = function(form, options){
4632 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
4633 this.reader = this.form.reader;
4636 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
4641 Roo.Ajax.request(Roo.apply(
4642 this.createCallback(), {
4643 method:this.getMethod(),
4644 url:this.getUrl(false),
4645 params:this.getParams()
4649 success : function(response){
4651 var result = this.processResponse(response);
4652 if(result === true || !result.success || !result.data){
4653 this.failureType = Roo.form.Action.LOAD_FAILURE;
4654 this.form.afterAction(this, false);
4657 this.form.clearInvalid();
4658 this.form.setValues(result.data);
4659 this.form.afterAction(this, true);
4662 handleResponse : function(response){
4663 if(this.form.reader){
4664 var rs = this.form.reader.read(response);
4665 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
4667 success : rs.success,
4671 return Roo.decode(response.responseText);
4675 Roo.form.Action.ACTION_TYPES = {
4676 'load' : Roo.form.Action.Load,
4677 'submit' : Roo.form.Action.Submit
4686 * @class Roo.bootstrap.Form
4687 * @extends Roo.bootstrap.Component
4688 * Bootstrap Form class
4689 * @cfg {String} method GET | POST (default POST)
4690 * @cfg {String} labelAlign top | left (default top)
4691 * @cfg {String} align left | right - for navbars
4696 * @param {Object} config The config object
4700 Roo.bootstrap.Form = function(config){
4701 Roo.bootstrap.Form.superclass.constructor.call(this, config);
4704 * @event clientvalidation
4705 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
4706 * @param {Form} this
4707 * @param {Boolean} valid true if the form has passed client-side validation
4709 clientvalidation: true,
4711 * @event beforeaction
4712 * Fires before any action is performed. Return false to cancel the action.
4713 * @param {Form} this
4714 * @param {Action} action The action to be performed
4718 * @event actionfailed
4719 * Fires when an action fails.
4720 * @param {Form} this
4721 * @param {Action} action The action that failed
4723 actionfailed : true,
4725 * @event actioncomplete
4726 * Fires when an action is completed.
4727 * @param {Form} this
4728 * @param {Action} action The action that completed
4730 actioncomplete : true
4735 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
4738 * @cfg {String} method
4739 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
4744 * The URL to use for form actions if one isn't supplied in the action options.
4747 * @cfg {Boolean} fileUpload
4748 * Set to true if this form is a file upload.
4752 * @cfg {Object} baseParams
4753 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
4757 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
4761 * @cfg {Sting} align (left|right) for navbar forms
4766 activeAction : null,
4769 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
4770 * element by passing it or its id or mask the form itself by passing in true.
4773 waitMsgTarget : false,
4778 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
4779 * element by passing it or its id or mask the form itself by passing in true.
4783 getAutoCreate : function(){
4787 method : this.method || 'POST',
4788 id : this.id || Roo.id(),
4791 if (this.parent().xtype.match(/^Nav/)) {
4792 cfg.cls = 'navbar-form navbar-' + this.align;
4796 if (this.labelAlign == 'left' ) {
4797 cfg.cls += ' form-horizontal';
4803 initEvents : function()
4805 this.el.on('submit', this.onSubmit, this);
4810 onSubmit : function(e){
4815 * Returns true if client-side validation on the form is successful.
4818 isValid : function(){
4819 var items = this.getItems();
4821 items.each(function(f){
4830 * Returns true if any fields in this form have changed since their original load.
4833 isDirty : function(){
4835 var items = this.getItems();
4836 items.each(function(f){
4846 * Performs a predefined action (submit or load) or custom actions you define on this form.
4847 * @param {String} actionName The name of the action type
4848 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
4849 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
4850 * accept other config options):
4852 Property Type Description
4853 ---------------- --------------- ----------------------------------------------------------------------------------
4854 url String The url for the action (defaults to the form's url)
4855 method String The form method to use (defaults to the form's method, or POST if not defined)
4856 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
4857 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
4858 validate the form on the client (defaults to false)
4860 * @return {BasicForm} this
4862 doAction : function(action, options){
4863 if(typeof action == 'string'){
4864 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
4866 if(this.fireEvent('beforeaction', this, action) !== false){
4867 this.beforeAction(action);
4868 action.run.defer(100, action);
4874 beforeAction : function(action){
4875 var o = action.options;
4877 // not really supported yet.. ??
4879 //if(this.waitMsgTarget === true){
4880 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
4881 //}else if(this.waitMsgTarget){
4882 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
4883 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
4885 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
4891 afterAction : function(action, success){
4892 this.activeAction = null;
4893 var o = action.options;
4895 //if(this.waitMsgTarget === true){
4897 //}else if(this.waitMsgTarget){
4898 // this.waitMsgTarget.unmask();
4900 // Roo.MessageBox.updateProgress(1);
4901 // Roo.MessageBox.hide();
4908 Roo.callback(o.success, o.scope, [this, action]);
4909 this.fireEvent('actioncomplete', this, action);
4913 // failure condition..
4914 // we have a scenario where updates need confirming.
4915 // eg. if a locking scenario exists..
4916 // we look for { errors : { needs_confirm : true }} in the response.
4918 (typeof(action.result) != 'undefined') &&
4919 (typeof(action.result.errors) != 'undefined') &&
4920 (typeof(action.result.errors.needs_confirm) != 'undefined')
4923 Roo.log("not supported yet");
4926 Roo.MessageBox.confirm(
4927 "Change requires confirmation",
4928 action.result.errorMsg,
4933 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
4943 Roo.callback(o.failure, o.scope, [this, action]);
4944 // show an error message if no failed handler is set..
4945 if (!this.hasListener('actionfailed')) {
4946 Roo.log("need to add dialog support");
4948 Roo.MessageBox.alert("Error",
4949 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
4950 action.result.errorMsg :
4951 "Saving Failed, please check your entries or try again"
4956 this.fireEvent('actionfailed', this, action);
4961 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
4962 * @param {String} id The value to search for
4965 findField : function(id){
4966 var items = this.getItems();
4967 var field = items.get(id);
4969 items.each(function(f){
4970 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
4977 return field || null;
4980 * Mark fields in this form invalid in bulk.
4981 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
4982 * @return {BasicForm} this
4984 markInvalid : function(errors){
4985 if(errors instanceof Array){
4986 for(var i = 0, len = errors.length; i < len; i++){
4987 var fieldError = errors[i];
4988 var f = this.findField(fieldError.id);
4990 f.markInvalid(fieldError.msg);
4996 if(typeof errors[id] != 'function' && (field = this.findField(id))){
4997 field.markInvalid(errors[id]);
5001 //Roo.each(this.childForms || [], function (f) {
5002 // f.markInvalid(errors);
5009 * Set values for fields in this form in bulk.
5010 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
5011 * @return {BasicForm} this
5013 setValues : function(values){
5014 if(values instanceof Array){ // array of objects
5015 for(var i = 0, len = values.length; i < len; i++){
5017 var f = this.findField(v.id);
5019 f.setValue(v.value);
5020 if(this.trackResetOnLoad){
5021 f.originalValue = f.getValue();
5025 }else{ // object hash
5028 if(typeof values[id] != 'function' && (field = this.findField(id))){
5030 if (field.setFromData &&
5032 field.displayField &&
5033 // combos' with local stores can
5034 // be queried via setValue()
5035 // to set their value..
5036 (field.store && !field.store.isLocal)
5040 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
5041 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
5042 field.setFromData(sd);
5045 field.setValue(values[id]);
5049 if(this.trackResetOnLoad){
5050 field.originalValue = field.getValue();
5056 //Roo.each(this.childForms || [], function (f) {
5057 // f.setValues(values);
5064 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
5065 * they are returned as an array.
5066 * @param {Boolean} asString
5069 getValues : function(asString){
5070 //if (this.childForms) {
5071 // copy values from the child forms
5072 // Roo.each(this.childForms, function (f) {
5073 // this.setValues(f.getValues());
5079 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
5080 if(asString === true){
5083 return Roo.urlDecode(fs);
5087 * Returns the fields in this form as an object with key/value pairs.
5088 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
5091 getFieldValues : function(with_hidden)
5093 var items = this.getItems();
5095 items.each(function(f){
5099 var v = f.getValue();
5100 if (f.inputType =='radio') {
5101 if (typeof(ret[f.getName()]) == 'undefined') {
5102 ret[f.getName()] = ''; // empty..
5105 if (!f.el.dom.checked) {
5113 // not sure if this supported any more..
5114 if ((typeof(v) == 'object') && f.getRawValue) {
5115 v = f.getRawValue() ; // dates..
5117 // combo boxes where name != hiddenName...
5118 if (f.name != f.getName()) {
5119 ret[f.name] = f.getRawValue();
5121 ret[f.getName()] = v;
5128 * Clears all invalid messages in this form.
5129 * @return {BasicForm} this
5131 clearInvalid : function(){
5132 var items = this.getItems();
5134 items.each(function(f){
5145 * @return {BasicForm} this
5148 var items = this.getItems();
5149 items.each(function(f){
5153 Roo.each(this.childForms || [], function (f) {
5160 getItems : function()
5162 var r=new Roo.util.MixedCollection(false, function(o){
5163 return o.id || (o.id = Roo.id());
5165 var iter = function(el) {
5172 Roo.each(el.items,function(e) {
5191 * Ext JS Library 1.1.1
5192 * Copyright(c) 2006-2007, Ext JS, LLC.
5194 * Originally Released Under LGPL - original licence link has changed is not relivant.
5197 * <script type="text/javascript">
5200 * @class Roo.form.VTypes
5201 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
5204 Roo.form.VTypes = function(){
5205 // closure these in so they are only created once.
5206 var alpha = /^[a-zA-Z_]+$/;
5207 var alphanum = /^[a-zA-Z0-9_]+$/;
5208 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
5209 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
5211 // All these messages and functions are configurable
5214 * The function used to validate email addresses
5215 * @param {String} value The email address
5217 'email' : function(v){
5218 return email.test(v);
5221 * The error text to display when the email validation function returns false
5224 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
5226 * The keystroke filter mask to be applied on email input
5229 'emailMask' : /[a-z0-9_\.\-@]/i,
5232 * The function used to validate URLs
5233 * @param {String} value The URL
5235 'url' : function(v){
5239 * The error text to display when the url validation function returns false
5242 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
5245 * The function used to validate alpha values
5246 * @param {String} value The value
5248 'alpha' : function(v){
5249 return alpha.test(v);
5252 * The error text to display when the alpha validation function returns false
5255 'alphaText' : 'This field should only contain letters and _',
5257 * The keystroke filter mask to be applied on alpha input
5260 'alphaMask' : /[a-z_]/i,
5263 * The function used to validate alphanumeric values
5264 * @param {String} value The value
5266 'alphanum' : function(v){
5267 return alphanum.test(v);
5270 * The error text to display when the alphanumeric validation function returns false
5273 'alphanumText' : 'This field should only contain letters, numbers and _',
5275 * The keystroke filter mask to be applied on alphanumeric input
5278 'alphanumMask' : /[a-z0-9_]/i
5288 * @class Roo.bootstrap.Input
5289 * @extends Roo.bootstrap.Component
5290 * Bootstrap Input class
5291 * @cfg {Boolean} disabled is it disabled
5292 * @cfg {String} fieldLabel - the label associated
5293 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
5294 * @cfg {String} name name of the input
5295 * @cfg {string} fieldLabel - the label associated
5296 * @cfg {string} inputType - input / file submit ...
5297 * @cfg {string} placeholder - placeholder to put in text.
5298 * @cfg {string} before - input group add on before
5299 * @cfg {string} after - input group add on after
5300 * @cfg {string} size - (lg|sm) or leave empty..
5301 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
5302 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
5303 * @cfg {Number} md colspan out of 12 for computer-sized screens
5304 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
5305 * @cfg {string} value default value of the input
5306 * @cfg {Number} labelWidth set the width of label (0-12)
5307 * @cfg {String} labelAlign (top|left)
5308 * @cfg {Boolean} readOnly Specifies that the field should be read-only
5312 * Create a new Input
5313 * @param {Object} config The config object
5316 Roo.bootstrap.Input = function(config){
5317 Roo.bootstrap.Input.superclass.constructor.call(this, config);
5322 * Fires when this field receives input focus.
5323 * @param {Roo.form.Field} this
5328 * Fires when this field loses input focus.
5329 * @param {Roo.form.Field} this
5334 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
5335 * {@link Roo.EventObject#getKey} to determine which key was pressed.
5336 * @param {Roo.form.Field} this
5337 * @param {Roo.EventObject} e The event object
5342 * Fires just before the field blurs if the field value has changed.
5343 * @param {Roo.form.Field} this
5344 * @param {Mixed} newValue The new value
5345 * @param {Mixed} oldValue The original value
5350 * Fires after the field has been marked as invalid.
5351 * @param {Roo.form.Field} this
5352 * @param {String} msg The validation message
5357 * Fires after the field has been validated with no errors.
5358 * @param {Roo.form.Field} this
5363 * Fires after the key up
5364 * @param {Roo.form.Field} this
5365 * @param {Roo.EventObject} e The event Object
5371 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
5373 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
5374 automatic validation (defaults to "keyup").
5376 validationEvent : "keyup",
5378 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
5380 validateOnBlur : true,
5382 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
5384 validationDelay : 250,
5386 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
5388 focusClass : "x-form-focus", // not needed???
5392 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
5394 invalidClass : "has-error",
5397 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
5399 selectOnFocus : false,
5402 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
5406 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
5411 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
5413 disableKeyFilter : false,
5416 * @cfg {Boolean} disabled True to disable the field (defaults to false).
5420 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
5424 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
5426 blankText : "This field is required",
5429 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
5433 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
5435 maxLength : Number.MAX_VALUE,
5437 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
5439 minLengthText : "The minimum length for this field is {0}",
5441 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
5443 maxLengthText : "The maximum length for this field is {0}",
5447 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
5448 * If available, this function will be called only after the basic validators all return true, and will be passed the
5449 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
5453 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
5454 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
5455 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
5459 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
5482 parentLabelAlign : function()
5485 while (parent.parent()) {
5486 parent = parent.parent();
5487 if (typeof(parent.labelAlign) !='undefined') {
5488 return parent.labelAlign;
5495 getAutoCreate : function(){
5497 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
5503 if(this.inputType != 'hidden'){
5504 cfg.cls = 'form-group' //input-group
5510 type : this.inputType,
5512 cls : 'form-control',
5513 placeholder : this.placeholder || ''
5517 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
5518 input.maxLength = this.maxLength;
5521 if (this.disabled) {
5522 input.disabled=true;
5525 if (this.readOnly) {
5526 input.readonly=true;
5530 input.name = this.name;
5533 input.cls += ' input-' + this.size;
5536 ['xs','sm','md','lg'].map(function(size){
5537 if (settings[size]) {
5538 cfg.cls += ' col-' + size + '-' + settings[size];
5542 var inputblock = input;
5544 if (this.before || this.after) {
5547 cls : 'input-group',
5551 inputblock.cn.push({
5553 cls : 'input-group-addon',
5557 inputblock.cn.push(input);
5559 inputblock.cn.push({
5561 cls : 'input-group-addon',
5568 if (align ==='left' && this.fieldLabel.length) {
5569 Roo.log("left and has label");
5575 cls : 'control-label col-sm-' + this.labelWidth,
5576 html : this.fieldLabel
5580 cls : "col-sm-" + (12 - this.labelWidth),
5587 } else if ( this.fieldLabel.length) {
5593 //cls : 'input-group-addon',
5594 html : this.fieldLabel
5604 Roo.log(" no label && no align");
5613 Roo.log('input-parentType: ' + this.parentType);
5615 if (this.parentType === 'Navbar' && this.parent().bar) {
5616 cfg.cls += ' navbar-form';
5624 * return the real input element.
5626 inputEl: function ()
5628 return this.el.select('input.form-control',true).first();
5630 setDisabled : function(v)
5632 var i = this.inputEl().dom;
5634 i.removeAttribute('disabled');
5638 i.setAttribute('disabled','true');
5640 initEvents : function()
5643 this.inputEl().on("keydown" , this.fireKey, this);
5644 this.inputEl().on("focus", this.onFocus, this);
5645 this.inputEl().on("blur", this.onBlur, this);
5647 this.inputEl().relayEvent('keyup', this);
5649 // reference to original value for reset
5650 this.originalValue = this.getValue();
5651 //Roo.form.TextField.superclass.initEvents.call(this);
5652 if(this.validationEvent == 'keyup'){
5653 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
5654 this.inputEl().on('keyup', this.filterValidation, this);
5656 else if(this.validationEvent !== false){
5657 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
5660 if(this.selectOnFocus){
5661 this.on("focus", this.preFocus, this);
5664 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
5665 this.inputEl().on("keypress", this.filterKeys, this);
5668 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
5669 this.el.on("click", this.autoSize, this);
5672 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
5673 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
5677 filterValidation : function(e){
5678 if(!e.isNavKeyPress()){
5679 this.validationTask.delay(this.validationDelay);
5683 * Validates the field value
5684 * @return {Boolean} True if the value is valid, else false
5686 validate : function(){
5687 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
5688 if(this.disabled || this.validateValue(this.getRawValue())){
5689 this.clearInvalid();
5697 * Validates a value according to the field's validation rules and marks the field as invalid
5698 * if the validation fails
5699 * @param {Mixed} value The value to validate
5700 * @return {Boolean} True if the value is valid, else false
5702 validateValue : function(value){
5703 if(value.length < 1) { // if it's blank
5704 if(this.allowBlank){
5705 this.clearInvalid();
5708 this.markInvalid(this.blankText);
5712 if(value.length < this.minLength){
5713 this.markInvalid(String.format(this.minLengthText, this.minLength));
5716 if(value.length > this.maxLength){
5717 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
5721 var vt = Roo.form.VTypes;
5722 if(!vt[this.vtype](value, this)){
5723 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
5727 if(typeof this.validator == "function"){
5728 var msg = this.validator(value);
5730 this.markInvalid(msg);
5734 if(this.regex && !this.regex.test(value)){
5735 this.markInvalid(this.regexText);
5744 fireKey : function(e){
5745 //Roo.log('field ' + e.getKey());
5746 if(e.isNavKeyPress()){
5747 this.fireEvent("specialkey", this, e);
5750 focus : function (selectText){
5752 this.inputEl().focus();
5753 if(selectText === true){
5754 this.inputEl().dom.select();
5760 onFocus : function(){
5761 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
5762 // this.el.addClass(this.focusClass);
5765 this.hasFocus = true;
5766 this.startValue = this.getValue();
5767 this.fireEvent("focus", this);
5771 beforeBlur : Roo.emptyFn,
5775 onBlur : function(){
5777 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
5778 //this.el.removeClass(this.focusClass);
5780 this.hasFocus = false;
5781 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
5784 var v = this.getValue();
5785 if(String(v) !== String(this.startValue)){
5786 this.fireEvent('change', this, v, this.startValue);
5788 this.fireEvent("blur", this);
5792 * Resets the current field value to the originally loaded value and clears any validation messages
5795 this.setValue(this.originalValue);
5796 this.clearInvalid();
5799 * Returns the name of the field
5800 * @return {Mixed} name The name field
5802 getName: function(){
5806 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
5807 * @return {Mixed} value The field value
5809 getValue : function(){
5810 return this.inputEl().getValue();
5813 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
5814 * @return {Mixed} value The field value
5816 getRawValue : function(){
5817 var v = this.inputEl().getValue();
5823 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
5824 * @param {Mixed} value The value to set
5826 setRawValue : function(v){
5827 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
5830 selectText : function(start, end){
5831 var v = this.getRawValue();
5833 start = start === undefined ? 0 : start;
5834 end = end === undefined ? v.length : end;
5835 var d = this.inputEl().dom;
5836 if(d.setSelectionRange){
5837 d.setSelectionRange(start, end);
5838 }else if(d.createTextRange){
5839 var range = d.createTextRange();
5840 range.moveStart("character", start);
5841 range.moveEnd("character", v.length-end);
5848 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
5849 * @param {Mixed} value The value to set
5851 setValue : function(v){
5854 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
5860 processValue : function(value){
5861 if(this.stripCharsRe){
5862 var newValue = value.replace(this.stripCharsRe, '');
5863 if(newValue !== value){
5864 this.setRawValue(newValue);
5871 preFocus : function(){
5873 if(this.selectOnFocus){
5874 this.inputEl().dom.select();
5877 filterKeys : function(e){
5879 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
5882 var c = e.getCharCode(), cc = String.fromCharCode(c);
5883 if(Roo.isIE && (e.isSpecialKey() || !cc)){
5886 if(!this.maskRe.test(cc)){
5891 * Clear any invalid styles/messages for this field
5893 clearInvalid : function(){
5895 if(!this.el || this.preventMark){ // not rendered
5898 this.el.removeClass(this.invalidClass);
5900 switch(this.msgTarget){
5902 this.el.dom.qtip = '';
5905 this.el.dom.title = '';
5909 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
5914 this.errorIcon.dom.qtip = '';
5915 this.errorIcon.hide();
5916 this.un('resize', this.alignErrorIcon, this);
5920 var t = Roo.getDom(this.msgTarget);
5922 t.style.display = 'none';
5926 this.fireEvent('valid', this);
5929 * Mark this field as invalid
5930 * @param {String} msg The validation message
5932 markInvalid : function(msg){
5933 if(!this.el || this.preventMark){ // not rendered
5936 this.el.addClass(this.invalidClass);
5938 msg = msg || this.invalidText;
5939 switch(this.msgTarget){
5941 this.el.dom.qtip = msg;
5942 this.el.dom.qclass = 'x-form-invalid-tip';
5943 if(Roo.QuickTips){ // fix for floating editors interacting with DND
5944 Roo.QuickTips.enable();
5948 this.el.dom.title = msg;
5952 var elp = this.el.findParent('.x-form-element', 5, true);
5953 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
5954 this.errorEl.setWidth(elp.getWidth(true)-20);
5956 this.errorEl.update(msg);
5957 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
5960 if(!this.errorIcon){
5961 var elp = this.el.findParent('.x-form-element', 5, true);
5962 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
5964 this.alignErrorIcon();
5965 this.errorIcon.dom.qtip = msg;
5966 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
5967 this.errorIcon.show();
5968 this.on('resize', this.alignErrorIcon, this);
5971 var t = Roo.getDom(this.msgTarget);
5973 t.style.display = this.msgDisplay;
5977 this.fireEvent('invalid', this, msg);
5980 SafariOnKeyDown : function(event)
5982 // this is a workaround for a password hang bug on chrome/ webkit.
5984 var isSelectAll = false;
5986 if(this.inputEl().dom.selectionEnd > 0){
5987 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
5989 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
5990 event.preventDefault();
5995 if(isSelectAll){ // backspace and delete key
5997 event.preventDefault();
5998 // this is very hacky as keydown always get's upper case.
6000 var cc = String.fromCharCode(event.getCharCode());
6001 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
6005 adjustWidth : function(tag, w){
6006 tag = tag.toLowerCase();
6007 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
6008 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
6012 if(tag == 'textarea'){
6015 }else if(Roo.isOpera){
6019 if(tag == 'textarea'){
6038 * @class Roo.bootstrap.TextArea
6039 * @extends Roo.bootstrap.Input
6040 * Bootstrap TextArea class
6041 * @cfg {Number} cols Specifies the visible width of a text area
6042 * @cfg {Number} rows Specifies the visible number of lines in a text area
6043 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
6044 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
6045 * @cfg {string} html text
6048 * Create a new TextArea
6049 * @param {Object} config The config object
6052 Roo.bootstrap.TextArea = function(config){
6053 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
6057 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
6067 getAutoCreate : function(){
6069 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6080 value : this.value || '',
6081 html: this.html || '',
6082 cls : 'form-control',
6083 placeholder : this.placeholder || ''
6087 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6088 input.maxLength = this.maxLength;
6092 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
6096 input.cols = this.cols;
6099 if (this.readOnly) {
6100 input.readonly = true;
6104 input.name = this.name;
6108 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
6112 ['xs','sm','md','lg'].map(function(size){
6113 if (settings[size]) {
6114 cfg.cls += ' col-' + size + '-' + settings[size];
6118 var inputblock = input;
6120 if (this.before || this.after) {
6123 cls : 'input-group',
6127 inputblock.cn.push({
6129 cls : 'input-group-addon',
6133 inputblock.cn.push(input);
6135 inputblock.cn.push({
6137 cls : 'input-group-addon',
6144 if (align ==='left' && this.fieldLabel.length) {
6145 Roo.log("left and has label");
6151 cls : 'control-label col-sm-' + this.labelWidth,
6152 html : this.fieldLabel
6156 cls : "col-sm-" + (12 - this.labelWidth),
6163 } else if ( this.fieldLabel.length) {
6169 //cls : 'input-group-addon',
6170 html : this.fieldLabel
6180 Roo.log(" no label && no align");
6190 if (this.disabled) {
6191 input.disabled=true;
6198 * return the real textarea element.
6200 inputEl: function ()
6202 return this.el.select('textarea.form-control',true).first();
6210 * trigger field - base class for combo..
6215 * @class Roo.bootstrap.TriggerField
6216 * @extends Roo.bootstrap.Input
6217 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
6218 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
6219 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
6220 * for which you can provide a custom implementation. For example:
6222 var trigger = new Roo.bootstrap.TriggerField();
6223 trigger.onTriggerClick = myTriggerFn;
6224 trigger.applyTo('my-field');
6227 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
6228 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
6229 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
6230 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
6232 * Create a new TriggerField.
6233 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
6234 * to the base TextField)
6236 Roo.bootstrap.TriggerField = function(config){
6237 this.mimicing = false;
6238 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
6241 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
6243 * @cfg {String} triggerClass A CSS class to apply to the trigger
6246 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
6250 /** @cfg {Boolean} grow @hide */
6251 /** @cfg {Number} growMin @hide */
6252 /** @cfg {Number} growMax @hide */
6258 autoSize: Roo.emptyFn,
6265 actionMode : 'wrap',
6269 getAutoCreate : function(){
6271 var parent = this.parent();
6273 var align = this.parentLabelAlign();
6278 cls: 'form-group' //input-group
6285 type : this.inputType,
6286 cls : 'form-control',
6287 autocomplete: 'off',
6288 placeholder : this.placeholder || ''
6292 input.name = this.name;
6295 input.cls += ' input-' + this.size;
6298 if (this.disabled) {
6299 input.disabled=true;
6302 var inputblock = input;
6304 if (this.before || this.after) {
6307 cls : 'input-group',
6311 inputblock.cn.push({
6313 cls : 'input-group-addon',
6317 inputblock.cn.push(input);
6319 inputblock.cn.push({
6321 cls : 'input-group-addon',
6334 cls: 'form-hidden-field'
6342 Roo.log('multiple');
6350 cls: 'form-hidden-field'
6354 cls: 'select2-choices',
6358 cls: 'select2-search-field',
6371 cls: 'select2-container input-group',
6376 cls: 'typeahead typeahead-long dropdown-menu',
6377 style: 'display:none'
6385 cls : 'input-group-addon btn dropdown-toggle',
6393 cls: 'combobox-clear',
6407 combobox.cls += ' select2-container-multi';
6410 if (align ==='left' && this.fieldLabel.length) {
6412 Roo.log("left and has label");
6418 cls : 'control-label col-sm-' + this.labelWidth,
6419 html : this.fieldLabel
6423 cls : "col-sm-" + (12 - this.labelWidth),
6430 } else if ( this.fieldLabel.length) {
6436 //cls : 'input-group-addon',
6437 html : this.fieldLabel
6447 Roo.log(" no label && no align");
6454 ['xs','sm','md','lg'].map(function(size){
6455 if (settings[size]) {
6456 cfg.cls += ' col-' + size + '-' + settings[size];
6467 onResize : function(w, h){
6468 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
6469 // if(typeof w == 'number'){
6470 // var x = w - this.trigger.getWidth();
6471 // this.inputEl().setWidth(this.adjustWidth('input', x));
6472 // this.trigger.setStyle('left', x+'px');
6477 adjustSize : Roo.BoxComponent.prototype.adjustSize,
6480 getResizeEl : function(){
6481 return this.inputEl();
6485 getPositionEl : function(){
6486 return this.inputEl();
6490 alignErrorIcon : function(){
6491 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
6495 initEvents : function(){
6497 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
6498 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
6500 this.trigger = this.el.select('span.dropdown-toggle',true).first();
6501 if(this.hideTrigger){
6502 this.trigger.setDisplayed(false);
6504 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
6508 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
6511 //this.trigger.addClassOnOver('x-form-trigger-over');
6512 //this.trigger.addClassOnClick('x-form-trigger-click');
6515 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
6520 initTrigger : function(){
6525 onDestroy : function(){
6527 this.trigger.removeAllListeners();
6528 // this.trigger.remove();
6531 // this.wrap.remove();
6533 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
6537 onFocus : function(){
6538 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
6541 this.wrap.addClass('x-trigger-wrap-focus');
6542 this.mimicing = true;
6543 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
6544 if(this.monitorTab){
6545 this.el.on("keydown", this.checkTab, this);
6552 checkTab : function(e){
6553 if(e.getKey() == e.TAB){
6559 onBlur : function(){
6564 mimicBlur : function(e, t){
6566 if(!this.wrap.contains(t) && this.validateBlur()){
6573 triggerBlur : function(){
6574 this.mimicing = false;
6575 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
6576 if(this.monitorTab){
6577 this.el.un("keydown", this.checkTab, this);
6579 //this.wrap.removeClass('x-trigger-wrap-focus');
6580 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
6584 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
6585 validateBlur : function(e, t){
6590 onDisable : function(){
6591 Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
6593 // this.wrap.addClass('x-item-disabled');
6598 onEnable : function(){
6599 Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
6601 // this.el.removeClass('x-item-disabled');
6606 onShow : function(){
6607 var ae = this.getActionEl();
6610 ae.dom.style.display = '';
6611 ae.dom.style.visibility = 'visible';
6617 onHide : function(){
6618 var ae = this.getActionEl();
6619 ae.dom.style.display = 'none';
6623 * The function that should handle the trigger's click event. This method does nothing by default until overridden
6624 * by an implementing function.
6626 * @param {EventObject} e
6628 onTriggerClick : Roo.emptyFn
6632 * Ext JS Library 1.1.1
6633 * Copyright(c) 2006-2007, Ext JS, LLC.
6635 * Originally Released Under LGPL - original licence link has changed is not relivant.
6638 * <script type="text/javascript">
6643 * @class Roo.data.SortTypes
6645 * Defines the default sorting (casting?) comparison functions used when sorting data.
6647 Roo.data.SortTypes = {
6649 * Default sort that does nothing
6650 * @param {Mixed} s The value being converted
6651 * @return {Mixed} The comparison value
6658 * The regular expression used to strip tags
6662 stripTagsRE : /<\/?[^>]+>/gi,
6665 * Strips all HTML tags to sort on text only
6666 * @param {Mixed} s The value being converted
6667 * @return {String} The comparison value
6669 asText : function(s){
6670 return String(s).replace(this.stripTagsRE, "");
6674 * Strips all HTML tags to sort on text only - Case insensitive
6675 * @param {Mixed} s The value being converted
6676 * @return {String} The comparison value
6678 asUCText : function(s){
6679 return String(s).toUpperCase().replace(this.stripTagsRE, "");
6683 * Case insensitive string
6684 * @param {Mixed} s The value being converted
6685 * @return {String} The comparison value
6687 asUCString : function(s) {
6688 return String(s).toUpperCase();
6693 * @param {Mixed} s The value being converted
6694 * @return {Number} The comparison value
6696 asDate : function(s) {
6700 if(s instanceof Date){
6703 return Date.parse(String(s));
6708 * @param {Mixed} s The value being converted
6709 * @return {Float} The comparison value
6711 asFloat : function(s) {
6712 var val = parseFloat(String(s).replace(/,/g, ""));
6713 if(isNaN(val)) val = 0;
6719 * @param {Mixed} s The value being converted
6720 * @return {Number} The comparison value
6722 asInt : function(s) {
6723 var val = parseInt(String(s).replace(/,/g, ""));
6724 if(isNaN(val)) val = 0;
6729 * Ext JS Library 1.1.1
6730 * Copyright(c) 2006-2007, Ext JS, LLC.
6732 * Originally Released Under LGPL - original licence link has changed is not relivant.
6735 * <script type="text/javascript">
6739 * @class Roo.data.Record
6740 * Instances of this class encapsulate both record <em>definition</em> information, and record
6741 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
6742 * to access Records cached in an {@link Roo.data.Store} object.<br>
6744 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
6745 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
6748 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
6750 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
6751 * {@link #create}. The parameters are the same.
6752 * @param {Array} data An associative Array of data values keyed by the field name.
6753 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
6754 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
6755 * not specified an integer id is generated.
6757 Roo.data.Record = function(data, id){
6758 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
6763 * Generate a constructor for a specific record layout.
6764 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
6765 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
6766 * Each field definition object may contain the following properties: <ul>
6767 * <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,
6768 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
6769 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
6770 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
6771 * is being used, then this is a string containing the javascript expression to reference the data relative to
6772 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
6773 * to the data item relative to the record element. If the mapping expression is the same as the field name,
6774 * this may be omitted.</p></li>
6775 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
6776 * <ul><li>auto (Default, implies no conversion)</li>
6781 * <li>date</li></ul></p></li>
6782 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
6783 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
6784 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
6785 * by the Reader into an object that will be stored in the Record. It is passed the
6786 * following parameters:<ul>
6787 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
6789 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
6791 * <br>usage:<br><pre><code>
6792 var TopicRecord = Roo.data.Record.create(
6793 {name: 'title', mapping: 'topic_title'},
6794 {name: 'author', mapping: 'username'},
6795 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
6796 {name: 'lastPost', mapping: 'post_time', type: 'date'},
6797 {name: 'lastPoster', mapping: 'user2'},
6798 {name: 'excerpt', mapping: 'post_text'}
6801 var myNewRecord = new TopicRecord({
6802 title: 'Do my job please',
6805 lastPost: new Date(),
6806 lastPoster: 'Animal',
6807 excerpt: 'No way dude!'
6809 myStore.add(myNewRecord);
6814 Roo.data.Record.create = function(o){
6816 f.superclass.constructor.apply(this, arguments);
6818 Roo.extend(f, Roo.data.Record);
6819 var p = f.prototype;
6820 p.fields = new Roo.util.MixedCollection(false, function(field){
6823 for(var i = 0, len = o.length; i < len; i++){
6824 p.fields.add(new Roo.data.Field(o[i]));
6826 f.getField = function(name){
6827 return p.fields.get(name);
6832 Roo.data.Record.AUTO_ID = 1000;
6833 Roo.data.Record.EDIT = 'edit';
6834 Roo.data.Record.REJECT = 'reject';
6835 Roo.data.Record.COMMIT = 'commit';
6837 Roo.data.Record.prototype = {
6839 * Readonly flag - true if this record has been modified.
6848 join : function(store){
6853 * Set the named field to the specified value.
6854 * @param {String} name The name of the field to set.
6855 * @param {Object} value The value to set the field to.
6857 set : function(name, value){
6858 if(this.data[name] == value){
6865 if(typeof this.modified[name] == 'undefined'){
6866 this.modified[name] = this.data[name];
6868 this.data[name] = value;
6869 if(!this.editing && this.store){
6870 this.store.afterEdit(this);
6875 * Get the value of the named field.
6876 * @param {String} name The name of the field to get the value of.
6877 * @return {Object} The value of the field.
6879 get : function(name){
6880 return this.data[name];
6884 beginEdit : function(){
6885 this.editing = true;
6890 cancelEdit : function(){
6891 this.editing = false;
6892 delete this.modified;
6896 endEdit : function(){
6897 this.editing = false;
6898 if(this.dirty && this.store){
6899 this.store.afterEdit(this);
6904 * Usually called by the {@link Roo.data.Store} which owns the Record.
6905 * Rejects all changes made to the Record since either creation, or the last commit operation.
6906 * Modified fields are reverted to their original values.
6908 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
6909 * of reject operations.
6911 reject : function(){
6912 var m = this.modified;
6914 if(typeof m[n] != "function"){
6915 this.data[n] = m[n];
6919 delete this.modified;
6920 this.editing = false;
6922 this.store.afterReject(this);
6927 * Usually called by the {@link Roo.data.Store} which owns the Record.
6928 * Commits all changes made to the Record since either creation, or the last commit operation.
6930 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
6931 * of commit operations.
6933 commit : function(){
6935 delete this.modified;
6936 this.editing = false;
6938 this.store.afterCommit(this);
6943 hasError : function(){
6944 return this.error != null;
6948 clearError : function(){
6953 * Creates a copy of this record.
6954 * @param {String} id (optional) A new record id if you don't want to use this record's id
6957 copy : function(newId) {
6958 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
6962 * Ext JS Library 1.1.1
6963 * Copyright(c) 2006-2007, Ext JS, LLC.
6965 * Originally Released Under LGPL - original licence link has changed is not relivant.
6968 * <script type="text/javascript">
6974 * @class Roo.data.Store
6975 * @extends Roo.util.Observable
6976 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
6977 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
6979 * 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
6980 * has no knowledge of the format of the data returned by the Proxy.<br>
6982 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
6983 * instances from the data object. These records are cached and made available through accessor functions.
6985 * Creates a new Store.
6986 * @param {Object} config A config object containing the objects needed for the Store to access data,
6987 * and read the data into Records.
6989 Roo.data.Store = function(config){
6990 this.data = new Roo.util.MixedCollection(false);
6991 this.data.getKey = function(o){
6994 this.baseParams = {};
7001 "multisort" : "_multisort"
7004 if(config && config.data){
7005 this.inlineData = config.data;
7009 Roo.apply(this, config);
7011 if(this.reader){ // reader passed
7012 this.reader = Roo.factory(this.reader, Roo.data);
7013 this.reader.xmodule = this.xmodule || false;
7014 if(!this.recordType){
7015 this.recordType = this.reader.recordType;
7017 if(this.reader.onMetaChange){
7018 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
7022 if(this.recordType){
7023 this.fields = this.recordType.prototype.fields;
7029 * @event datachanged
7030 * Fires when the data cache has changed, and a widget which is using this Store
7031 * as a Record cache should refresh its view.
7032 * @param {Store} this
7037 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
7038 * @param {Store} this
7039 * @param {Object} meta The JSON metadata
7044 * Fires when Records have been added to the Store
7045 * @param {Store} this
7046 * @param {Roo.data.Record[]} records The array of Records added
7047 * @param {Number} index The index at which the record(s) were added
7052 * Fires when a Record has been removed from the Store
7053 * @param {Store} this
7054 * @param {Roo.data.Record} record The Record that was removed
7055 * @param {Number} index The index at which the record was removed
7060 * Fires when a Record has been updated
7061 * @param {Store} this
7062 * @param {Roo.data.Record} record The Record that was updated
7063 * @param {String} operation The update operation being performed. Value may be one of:
7065 Roo.data.Record.EDIT
7066 Roo.data.Record.REJECT
7067 Roo.data.Record.COMMIT
7073 * Fires when the data cache has been cleared.
7074 * @param {Store} this
7079 * Fires before a request is made for a new data object. If the beforeload handler returns false
7080 * the load action will be canceled.
7081 * @param {Store} this
7082 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7086 * @event beforeloadadd
7087 * Fires after a new set of Records has been loaded.
7088 * @param {Store} this
7089 * @param {Roo.data.Record[]} records The Records that were loaded
7090 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7092 beforeloadadd : true,
7095 * Fires after a new set of Records has been loaded, before they are added to the store.
7096 * @param {Store} this
7097 * @param {Roo.data.Record[]} records The Records that were loaded
7098 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7099 * @params {Object} return from reader
7103 * @event loadexception
7104 * Fires if an exception occurs in the Proxy during loading.
7105 * Called with the signature of the Proxy's "loadexception" event.
7106 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
7109 * @param {Object} return from JsonData.reader() - success, totalRecords, records
7110 * @param {Object} load options
7111 * @param {Object} jsonData from your request (normally this contains the Exception)
7113 loadexception : true
7117 this.proxy = Roo.factory(this.proxy, Roo.data);
7118 this.proxy.xmodule = this.xmodule || false;
7119 this.relayEvents(this.proxy, ["loadexception"]);
7121 this.sortToggle = {};
7122 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
7124 Roo.data.Store.superclass.constructor.call(this);
7126 if(this.inlineData){
7127 this.loadData(this.inlineData);
7128 delete this.inlineData;
7132 Roo.extend(Roo.data.Store, Roo.util.Observable, {
7134 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
7135 * without a remote query - used by combo/forms at present.
7139 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
7142 * @cfg {Array} data Inline data to be loaded when the store is initialized.
7145 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
7146 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
7149 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
7150 * on any HTTP request
7153 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
7156 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
7160 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
7161 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
7166 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
7167 * loaded or when a record is removed. (defaults to false).
7169 pruneModifiedRecords : false,
7175 * Add Records to the Store and fires the add event.
7176 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
7178 add : function(records){
7179 records = [].concat(records);
7180 for(var i = 0, len = records.length; i < len; i++){
7181 records[i].join(this);
7183 var index = this.data.length;
7184 this.data.addAll(records);
7185 this.fireEvent("add", this, records, index);
7189 * Remove a Record from the Store and fires the remove event.
7190 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
7192 remove : function(record){
7193 var index = this.data.indexOf(record);
7194 this.data.removeAt(index);
7195 if(this.pruneModifiedRecords){
7196 this.modified.remove(record);
7198 this.fireEvent("remove", this, record, index);
7202 * Remove all Records from the Store and fires the clear event.
7204 removeAll : function(){
7206 if(this.pruneModifiedRecords){
7209 this.fireEvent("clear", this);
7213 * Inserts Records to the Store at the given index and fires the add event.
7214 * @param {Number} index The start index at which to insert the passed Records.
7215 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
7217 insert : function(index, records){
7218 records = [].concat(records);
7219 for(var i = 0, len = records.length; i < len; i++){
7220 this.data.insert(index, records[i]);
7221 records[i].join(this);
7223 this.fireEvent("add", this, records, index);
7227 * Get the index within the cache of the passed Record.
7228 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
7229 * @return {Number} The index of the passed Record. Returns -1 if not found.
7231 indexOf : function(record){
7232 return this.data.indexOf(record);
7236 * Get the index within the cache of the Record with the passed id.
7237 * @param {String} id The id of the Record to find.
7238 * @return {Number} The index of the Record. Returns -1 if not found.
7240 indexOfId : function(id){
7241 return this.data.indexOfKey(id);
7245 * Get the Record with the specified id.
7246 * @param {String} id The id of the Record to find.
7247 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
7249 getById : function(id){
7250 return this.data.key(id);
7254 * Get the Record at the specified index.
7255 * @param {Number} index The index of the Record to find.
7256 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
7258 getAt : function(index){
7259 return this.data.itemAt(index);
7263 * Returns a range of Records between specified indices.
7264 * @param {Number} startIndex (optional) The starting index (defaults to 0)
7265 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
7266 * @return {Roo.data.Record[]} An array of Records
7268 getRange : function(start, end){
7269 return this.data.getRange(start, end);
7273 storeOptions : function(o){
7274 o = Roo.apply({}, o);
7277 this.lastOptions = o;
7281 * Loads the Record cache from the configured Proxy using the configured Reader.
7283 * If using remote paging, then the first load call must specify the <em>start</em>
7284 * and <em>limit</em> properties in the options.params property to establish the initial
7285 * position within the dataset, and the number of Records to cache on each read from the Proxy.
7287 * <strong>It is important to note that for remote data sources, loading is asynchronous,
7288 * and this call will return before the new data has been loaded. Perform any post-processing
7289 * in a callback function, or in a "load" event handler.</strong>
7291 * @param {Object} options An object containing properties which control loading options:<ul>
7292 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
7293 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
7294 * passed the following arguments:<ul>
7295 * <li>r : Roo.data.Record[]</li>
7296 * <li>options: Options object from the load call</li>
7297 * <li>success: Boolean success indicator</li></ul></li>
7298 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
7299 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
7302 load : function(options){
7303 options = options || {};
7304 if(this.fireEvent("beforeload", this, options) !== false){
7305 this.storeOptions(options);
7306 var p = Roo.apply(options.params || {}, this.baseParams);
7307 // if meta was not loaded from remote source.. try requesting it.
7308 if (!this.reader.metaFromRemote) {
7311 if(this.sortInfo && this.remoteSort){
7312 var pn = this.paramNames;
7313 p[pn["sort"]] = this.sortInfo.field;
7314 p[pn["dir"]] = this.sortInfo.direction;
7316 if (this.multiSort) {
7317 var pn = this.paramNames;
7318 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
7321 this.proxy.load(p, this.reader, this.loadRecords, this, options);
7326 * Reloads the Record cache from the configured Proxy using the configured Reader and
7327 * the options from the last load operation performed.
7328 * @param {Object} options (optional) An object containing properties which may override the options
7329 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
7330 * the most recently used options are reused).
7332 reload : function(options){
7333 this.load(Roo.applyIf(options||{}, this.lastOptions));
7337 // Called as a callback by the Reader during a load operation.
7338 loadRecords : function(o, options, success){
7339 if(!o || success === false){
7340 if(success !== false){
7341 this.fireEvent("load", this, [], options, o);
7343 if(options.callback){
7344 options.callback.call(options.scope || this, [], options, false);
7348 // if data returned failure - throw an exception.
7349 if (o.success === false) {
7350 // show a message if no listener is registered.
7351 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
7352 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
7354 // loadmask wil be hooked into this..
7355 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
7358 var r = o.records, t = o.totalRecords || r.length;
7360 this.fireEvent("beforeloadadd", this, r, options, o);
7362 if(!options || options.add !== true){
7363 if(this.pruneModifiedRecords){
7366 for(var i = 0, len = r.length; i < len; i++){
7370 this.data = this.snapshot;
7371 delete this.snapshot;
7374 this.data.addAll(r);
7375 this.totalLength = t;
7377 this.fireEvent("datachanged", this);
7379 this.totalLength = Math.max(t, this.data.length+r.length);
7382 this.fireEvent("load", this, r, options, o);
7383 if(options.callback){
7384 options.callback.call(options.scope || this, r, options, true);
7390 * Loads data from a passed data block. A Reader which understands the format of the data
7391 * must have been configured in the constructor.
7392 * @param {Object} data The data block from which to read the Records. The format of the data expected
7393 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
7394 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
7396 loadData : function(o, append){
7397 var r = this.reader.readRecords(o);
7398 this.loadRecords(r, {add: append}, true);
7402 * Gets the number of cached records.
7404 * <em>If using paging, this may not be the total size of the dataset. If the data object
7405 * used by the Reader contains the dataset size, then the getTotalCount() function returns
7406 * the data set size</em>
7408 getCount : function(){
7409 return this.data.length || 0;
7413 * Gets the total number of records in the dataset as returned by the server.
7415 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
7416 * the dataset size</em>
7418 getTotalCount : function(){
7419 return this.totalLength || 0;
7423 * Returns the sort state of the Store as an object with two properties:
7425 field {String} The name of the field by which the Records are sorted
7426 direction {String} The sort order, "ASC" or "DESC"
7429 getSortState : function(){
7430 return this.sortInfo;
7434 applySort : function(){
7435 if(this.sortInfo && !this.remoteSort){
7436 var s = this.sortInfo, f = s.field;
7437 var st = this.fields.get(f).sortType;
7438 var fn = function(r1, r2){
7439 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
7440 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
7442 this.data.sort(s.direction, fn);
7443 if(this.snapshot && this.snapshot != this.data){
7444 this.snapshot.sort(s.direction, fn);
7450 * Sets the default sort column and order to be used by the next load operation.
7451 * @param {String} fieldName The name of the field to sort by.
7452 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
7454 setDefaultSort : function(field, dir){
7455 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
7460 * If remote sorting is used, the sort is performed on the server, and the cache is
7461 * reloaded. If local sorting is used, the cache is sorted internally.
7462 * @param {String} fieldName The name of the field to sort by.
7463 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
7465 sort : function(fieldName, dir){
7466 var f = this.fields.get(fieldName);
7468 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
7470 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
7471 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
7476 this.sortToggle[f.name] = dir;
7477 this.sortInfo = {field: f.name, direction: dir};
7478 if(!this.remoteSort){
7480 this.fireEvent("datachanged", this);
7482 this.load(this.lastOptions);
7487 * Calls the specified function for each of the Records in the cache.
7488 * @param {Function} fn The function to call. The Record is passed as the first parameter.
7489 * Returning <em>false</em> aborts and exits the iteration.
7490 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
7492 each : function(fn, scope){
7493 this.data.each(fn, scope);
7497 * Gets all records modified since the last commit. Modified records are persisted across load operations
7498 * (e.g., during paging).
7499 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
7501 getModifiedRecords : function(){
7502 return this.modified;
7506 createFilterFn : function(property, value, anyMatch){
7507 if(!value.exec){ // not a regex
7508 value = String(value);
7509 if(value.length == 0){
7512 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
7515 return value.test(r.data[property]);
7520 * Sums the value of <i>property</i> for each record between start and end and returns the result.
7521 * @param {String} property A field on your records
7522 * @param {Number} start The record index to start at (defaults to 0)
7523 * @param {Number} end The last record index to include (defaults to length - 1)
7524 * @return {Number} The sum
7526 sum : function(property, start, end){
7527 var rs = this.data.items, v = 0;
7529 end = (end || end === 0) ? end : rs.length-1;
7531 for(var i = start; i <= end; i++){
7532 v += (rs[i].data[property] || 0);
7538 * Filter the records by a specified property.
7539 * @param {String} field A field on your records
7540 * @param {String/RegExp} value Either a string that the field
7541 * should start with or a RegExp to test against the field
7542 * @param {Boolean} anyMatch True to match any part not just the beginning
7544 filter : function(property, value, anyMatch){
7545 var fn = this.createFilterFn(property, value, anyMatch);
7546 return fn ? this.filterBy(fn) : this.clearFilter();
7550 * Filter by a function. The specified function will be called with each
7551 * record in this data source. If the function returns true the record is included,
7552 * otherwise it is filtered.
7553 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
7554 * @param {Object} scope (optional) The scope of the function (defaults to this)
7556 filterBy : function(fn, scope){
7557 this.snapshot = this.snapshot || this.data;
7558 this.data = this.queryBy(fn, scope||this);
7559 this.fireEvent("datachanged", this);
7563 * Query the records by a specified property.
7564 * @param {String} field A field on your records
7565 * @param {String/RegExp} value Either a string that the field
7566 * should start with or a RegExp to test against the field
7567 * @param {Boolean} anyMatch True to match any part not just the beginning
7568 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
7570 query : function(property, value, anyMatch){
7571 var fn = this.createFilterFn(property, value, anyMatch);
7572 return fn ? this.queryBy(fn) : this.data.clone();
7576 * Query by a function. The specified function will be called with each
7577 * record in this data source. If the function returns true the record is included
7579 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
7580 * @param {Object} scope (optional) The scope of the function (defaults to this)
7581 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
7583 queryBy : function(fn, scope){
7584 var data = this.snapshot || this.data;
7585 return data.filterBy(fn, scope||this);
7589 * Collects unique values for a particular dataIndex from this store.
7590 * @param {String} dataIndex The property to collect
7591 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
7592 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
7593 * @return {Array} An array of the unique values
7595 collect : function(dataIndex, allowNull, bypassFilter){
7596 var d = (bypassFilter === true && this.snapshot) ?
7597 this.snapshot.items : this.data.items;
7598 var v, sv, r = [], l = {};
7599 for(var i = 0, len = d.length; i < len; i++){
7600 v = d[i].data[dataIndex];
7602 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
7611 * Revert to a view of the Record cache with no filtering applied.
7612 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
7614 clearFilter : function(suppressEvent){
7615 if(this.snapshot && this.snapshot != this.data){
7616 this.data = this.snapshot;
7617 delete this.snapshot;
7618 if(suppressEvent !== true){
7619 this.fireEvent("datachanged", this);
7625 afterEdit : function(record){
7626 if(this.modified.indexOf(record) == -1){
7627 this.modified.push(record);
7629 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
7633 afterReject : function(record){
7634 this.modified.remove(record);
7635 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
7639 afterCommit : function(record){
7640 this.modified.remove(record);
7641 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
7645 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
7646 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
7648 commitChanges : function(){
7649 var m = this.modified.slice(0);
7651 for(var i = 0, len = m.length; i < len; i++){
7657 * Cancel outstanding changes on all changed records.
7659 rejectChanges : function(){
7660 var m = this.modified.slice(0);
7662 for(var i = 0, len = m.length; i < len; i++){
7667 onMetaChange : function(meta, rtype, o){
7668 this.recordType = rtype;
7669 this.fields = rtype.prototype.fields;
7670 delete this.snapshot;
7671 this.sortInfo = meta.sortInfo || this.sortInfo;
7673 this.fireEvent('metachange', this, this.reader.meta);
7676 moveIndex : function(data, type)
7678 var index = this.indexOf(data);
7680 var newIndex = index + type;
7684 this.insert(newIndex, data);
7689 * Ext JS Library 1.1.1
7690 * Copyright(c) 2006-2007, Ext JS, LLC.
7692 * Originally Released Under LGPL - original licence link has changed is not relivant.
7695 * <script type="text/javascript">
7699 * @class Roo.data.SimpleStore
7700 * @extends Roo.data.Store
7701 * Small helper class to make creating Stores from Array data easier.
7702 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
7703 * @cfg {Array} fields An array of field definition objects, or field name strings.
7704 * @cfg {Array} data The multi-dimensional array of data
7706 * @param {Object} config
7708 Roo.data.SimpleStore = function(config){
7709 Roo.data.SimpleStore.superclass.constructor.call(this, {
7711 reader: new Roo.data.ArrayReader({
7714 Roo.data.Record.create(config.fields)
7716 proxy : new Roo.data.MemoryProxy(config.data)
7720 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
7722 * Ext JS Library 1.1.1
7723 * Copyright(c) 2006-2007, Ext JS, LLC.
7725 * Originally Released Under LGPL - original licence link has changed is not relivant.
7728 * <script type="text/javascript">
7733 * @extends Roo.data.Store
7734 * @class Roo.data.JsonStore
7735 * Small helper class to make creating Stores for JSON data easier. <br/>
7737 var store = new Roo.data.JsonStore({
7738 url: 'get-images.php',
7740 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
7743 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
7744 * JsonReader and HttpProxy (unless inline data is provided).</b>
7745 * @cfg {Array} fields An array of field definition objects, or field name strings.
7747 * @param {Object} config
7749 Roo.data.JsonStore = function(c){
7750 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
7751 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
7752 reader: new Roo.data.JsonReader(c, c.fields)
7755 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
7757 * Ext JS Library 1.1.1
7758 * Copyright(c) 2006-2007, Ext JS, LLC.
7760 * Originally Released Under LGPL - original licence link has changed is not relivant.
7763 * <script type="text/javascript">
7767 Roo.data.Field = function(config){
7768 if(typeof config == "string"){
7769 config = {name: config};
7771 Roo.apply(this, config);
7777 var st = Roo.data.SortTypes;
7778 // named sortTypes are supported, here we look them up
7779 if(typeof this.sortType == "string"){
7780 this.sortType = st[this.sortType];
7783 // set default sortType for strings and dates
7787 this.sortType = st.asUCString;
7790 this.sortType = st.asDate;
7793 this.sortType = st.none;
7798 var stripRe = /[\$,%]/g;
7800 // prebuilt conversion function for this field, instead of
7801 // switching every time we're reading a value
7803 var cv, dateFormat = this.dateFormat;
7808 cv = function(v){ return v; };
7811 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
7815 return v !== undefined && v !== null && v !== '' ?
7816 parseInt(String(v).replace(stripRe, ""), 10) : '';
7821 return v !== undefined && v !== null && v !== '' ?
7822 parseFloat(String(v).replace(stripRe, ""), 10) : '';
7827 cv = function(v){ return v === true || v === "true" || v == 1; };
7834 if(v instanceof Date){
7838 if(dateFormat == "timestamp"){
7839 return new Date(v*1000);
7841 return Date.parseDate(v, dateFormat);
7843 var parsed = Date.parse(v);
7844 return parsed ? new Date(parsed) : null;
7853 Roo.data.Field.prototype = {
7861 * Ext JS Library 1.1.1
7862 * Copyright(c) 2006-2007, Ext JS, LLC.
7864 * Originally Released Under LGPL - original licence link has changed is not relivant.
7867 * <script type="text/javascript">
7870 // Base class for reading structured data from a data source. This class is intended to be
7871 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
7874 * @class Roo.data.DataReader
7875 * Base class for reading structured data from a data source. This class is intended to be
7876 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
7879 Roo.data.DataReader = function(meta, recordType){
7883 this.recordType = recordType instanceof Array ?
7884 Roo.data.Record.create(recordType) : recordType;
7887 Roo.data.DataReader.prototype = {
7889 * Create an empty record
7890 * @param {Object} data (optional) - overlay some values
7891 * @return {Roo.data.Record} record created.
7893 newRow : function(d) {
7895 this.recordType.prototype.fields.each(function(c) {
7897 case 'int' : da[c.name] = 0; break;
7898 case 'date' : da[c.name] = new Date(); break;
7899 case 'float' : da[c.name] = 0.0; break;
7900 case 'boolean' : da[c.name] = false; break;
7901 default : da[c.name] = ""; break;
7905 return new this.recordType(Roo.apply(da, d));
7910 * Ext JS Library 1.1.1
7911 * Copyright(c) 2006-2007, Ext JS, LLC.
7913 * Originally Released Under LGPL - original licence link has changed is not relivant.
7916 * <script type="text/javascript">
7920 * @class Roo.data.DataProxy
7921 * @extends Roo.data.Observable
7922 * This class is an abstract base class for implementations which provide retrieval of
7923 * unformatted data objects.<br>
7925 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
7926 * (of the appropriate type which knows how to parse the data object) to provide a block of
7927 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
7929 * Custom implementations must implement the load method as described in
7930 * {@link Roo.data.HttpProxy#load}.
7932 Roo.data.DataProxy = function(){
7936 * Fires before a network request is made to retrieve a data object.
7937 * @param {Object} This DataProxy object.
7938 * @param {Object} params The params parameter to the load function.
7943 * Fires before the load method's callback is called.
7944 * @param {Object} This DataProxy object.
7945 * @param {Object} o The data object.
7946 * @param {Object} arg The callback argument object passed to the load function.
7950 * @event loadexception
7951 * Fires if an Exception occurs during data retrieval.
7952 * @param {Object} This DataProxy object.
7953 * @param {Object} o The data object.
7954 * @param {Object} arg The callback argument object passed to the load function.
7955 * @param {Object} e The Exception.
7957 loadexception : true
7959 Roo.data.DataProxy.superclass.constructor.call(this);
7962 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
7965 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
7969 * Ext JS Library 1.1.1
7970 * Copyright(c) 2006-2007, Ext JS, LLC.
7972 * Originally Released Under LGPL - original licence link has changed is not relivant.
7975 * <script type="text/javascript">
7978 * @class Roo.data.MemoryProxy
7979 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
7980 * to the Reader when its load method is called.
7982 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
7984 Roo.data.MemoryProxy = function(data){
7988 Roo.data.MemoryProxy.superclass.constructor.call(this);
7992 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
7994 * Load data from the requested source (in this case an in-memory
7995 * data object passed to the constructor), read the data object into
7996 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
7997 * process that block using the passed callback.
7998 * @param {Object} params This parameter is not used by the MemoryProxy class.
7999 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8000 * object into a block of Roo.data.Records.
8001 * @param {Function} callback The function into which to pass the block of Roo.data.records.
8002 * The function must be passed <ul>
8003 * <li>The Record block object</li>
8004 * <li>The "arg" argument from the load function</li>
8005 * <li>A boolean success indicator</li>
8007 * @param {Object} scope The scope in which to call the callback
8008 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8010 load : function(params, reader, callback, scope, arg){
8011 params = params || {};
8014 result = reader.readRecords(this.data);
8016 this.fireEvent("loadexception", this, arg, null, e);
8017 callback.call(scope, null, arg, false);
8020 callback.call(scope, result, arg, true);
8024 update : function(params, records){
8029 * Ext JS Library 1.1.1
8030 * Copyright(c) 2006-2007, Ext JS, LLC.
8032 * Originally Released Under LGPL - original licence link has changed is not relivant.
8035 * <script type="text/javascript">
8038 * @class Roo.data.HttpProxy
8039 * @extends Roo.data.DataProxy
8040 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
8041 * configured to reference a certain URL.<br><br>
8043 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
8044 * from which the running page was served.<br><br>
8046 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
8048 * Be aware that to enable the browser to parse an XML document, the server must set
8049 * the Content-Type header in the HTTP response to "text/xml".
8051 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
8052 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
8053 * will be used to make the request.
8055 Roo.data.HttpProxy = function(conn){
8056 Roo.data.HttpProxy.superclass.constructor.call(this);
8057 // is conn a conn config or a real conn?
8059 this.useAjax = !conn || !conn.events;
8063 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
8064 // thse are take from connection...
8067 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
8070 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
8071 * extra parameters to each request made by this object. (defaults to undefined)
8074 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
8075 * to each request made by this object. (defaults to undefined)
8078 * @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)
8081 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
8084 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
8090 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
8094 * Return the {@link Roo.data.Connection} object being used by this Proxy.
8095 * @return {Connection} The Connection object. This object may be used to subscribe to events on
8096 * a finer-grained basis than the DataProxy events.
8098 getConnection : function(){
8099 return this.useAjax ? Roo.Ajax : this.conn;
8103 * Load data from the configured {@link Roo.data.Connection}, read the data object into
8104 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
8105 * process that block using the passed callback.
8106 * @param {Object} params An object containing properties which are to be used as HTTP parameters
8107 * for the request to the remote server.
8108 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8109 * object into a block of Roo.data.Records.
8110 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
8111 * The function must be passed <ul>
8112 * <li>The Record block object</li>
8113 * <li>The "arg" argument from the load function</li>
8114 * <li>A boolean success indicator</li>
8116 * @param {Object} scope The scope in which to call the callback
8117 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8119 load : function(params, reader, callback, scope, arg){
8120 if(this.fireEvent("beforeload", this, params) !== false){
8122 params : params || {},
8124 callback : callback,
8129 callback : this.loadResponse,
8133 Roo.applyIf(o, this.conn);
8134 if(this.activeRequest){
8135 Roo.Ajax.abort(this.activeRequest);
8137 this.activeRequest = Roo.Ajax.request(o);
8139 this.conn.request(o);
8142 callback.call(scope||this, null, arg, false);
8147 loadResponse : function(o, success, response){
8148 delete this.activeRequest;
8150 this.fireEvent("loadexception", this, o, response);
8151 o.request.callback.call(o.request.scope, null, o.request.arg, false);
8156 result = o.reader.read(response);
8158 this.fireEvent("loadexception", this, o, response, e);
8159 o.request.callback.call(o.request.scope, null, o.request.arg, false);
8163 this.fireEvent("load", this, o, o.request.arg);
8164 o.request.callback.call(o.request.scope, result, o.request.arg, true);
8168 update : function(dataSet){
8173 updateResponse : function(dataSet){
8178 * Ext JS Library 1.1.1
8179 * Copyright(c) 2006-2007, Ext JS, LLC.
8181 * Originally Released Under LGPL - original licence link has changed is not relivant.
8184 * <script type="text/javascript">
8188 * @class Roo.data.ScriptTagProxy
8189 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
8190 * other than the originating domain of the running page.<br><br>
8192 * <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
8193 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
8195 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
8196 * source code that is used as the source inside a <script> tag.<br><br>
8198 * In order for the browser to process the returned data, the server must wrap the data object
8199 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
8200 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
8201 * depending on whether the callback name was passed:
8204 boolean scriptTag = false;
8205 String cb = request.getParameter("callback");
8208 response.setContentType("text/javascript");
8210 response.setContentType("application/x-json");
8212 Writer out = response.getWriter();
8214 out.write(cb + "(");
8216 out.print(dataBlock.toJsonString());
8223 * @param {Object} config A configuration object.
8225 Roo.data.ScriptTagProxy = function(config){
8226 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
8227 Roo.apply(this, config);
8228 this.head = document.getElementsByTagName("head")[0];
8231 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
8233 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
8235 * @cfg {String} url The URL from which to request the data object.
8238 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
8242 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
8243 * the server the name of the callback function set up by the load call to process the returned data object.
8244 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
8245 * javascript output which calls this named function passing the data object as its only parameter.
8247 callbackParam : "callback",
8249 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
8250 * name to the request.
8255 * Load data from the configured URL, read the data object into
8256 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
8257 * process that block using the passed callback.
8258 * @param {Object} params An object containing properties which are to be used as HTTP parameters
8259 * for the request to the remote server.
8260 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8261 * object into a block of Roo.data.Records.
8262 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
8263 * The function must be passed <ul>
8264 * <li>The Record block object</li>
8265 * <li>The "arg" argument from the load function</li>
8266 * <li>A boolean success indicator</li>
8268 * @param {Object} scope The scope in which to call the callback
8269 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8271 load : function(params, reader, callback, scope, arg){
8272 if(this.fireEvent("beforeload", this, params) !== false){
8274 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
8277 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
8279 url += "&_dc=" + (new Date().getTime());
8281 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
8284 cb : "stcCallback"+transId,
8285 scriptId : "stcScript"+transId,
8289 callback : callback,
8295 window[trans.cb] = function(o){
8296 conn.handleResponse(o, trans);
8299 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
8301 if(this.autoAbort !== false){
8305 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
8307 var script = document.createElement("script");
8308 script.setAttribute("src", url);
8309 script.setAttribute("type", "text/javascript");
8310 script.setAttribute("id", trans.scriptId);
8311 this.head.appendChild(script);
8315 callback.call(scope||this, null, arg, false);
8320 isLoading : function(){
8321 return this.trans ? true : false;
8325 * Abort the current server request.
8328 if(this.isLoading()){
8329 this.destroyTrans(this.trans);
8334 destroyTrans : function(trans, isLoaded){
8335 this.head.removeChild(document.getElementById(trans.scriptId));
8336 clearTimeout(trans.timeoutId);
8338 window[trans.cb] = undefined;
8340 delete window[trans.cb];
8343 // if hasn't been loaded, wait for load to remove it to prevent script error
8344 window[trans.cb] = function(){
8345 window[trans.cb] = undefined;
8347 delete window[trans.cb];
8354 handleResponse : function(o, trans){
8356 this.destroyTrans(trans, true);
8359 result = trans.reader.readRecords(o);
8361 this.fireEvent("loadexception", this, o, trans.arg, e);
8362 trans.callback.call(trans.scope||window, null, trans.arg, false);
8365 this.fireEvent("load", this, o, trans.arg);
8366 trans.callback.call(trans.scope||window, result, trans.arg, true);
8370 handleFailure : function(trans){
8372 this.destroyTrans(trans, false);
8373 this.fireEvent("loadexception", this, null, trans.arg);
8374 trans.callback.call(trans.scope||window, null, trans.arg, false);
8378 * Ext JS Library 1.1.1
8379 * Copyright(c) 2006-2007, Ext JS, LLC.
8381 * Originally Released Under LGPL - original licence link has changed is not relivant.
8384 * <script type="text/javascript">
8388 * @class Roo.data.JsonReader
8389 * @extends Roo.data.DataReader
8390 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
8391 * based on mappings in a provided Roo.data.Record constructor.
8393 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
8394 * in the reply previously.
8399 var RecordDef = Roo.data.Record.create([
8400 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
8401 {name: 'occupation'} // This field will use "occupation" as the mapping.
8403 var myReader = new Roo.data.JsonReader({
8404 totalProperty: "results", // The property which contains the total dataset size (optional)
8405 root: "rows", // The property which contains an Array of row objects
8406 id: "id" // The property within each row object that provides an ID for the record (optional)
8410 * This would consume a JSON file like this:
8412 { 'results': 2, 'rows': [
8413 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
8414 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
8417 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
8418 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
8419 * paged from the remote server.
8420 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
8421 * @cfg {String} root name of the property which contains the Array of row objects.
8422 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
8424 * Create a new JsonReader
8425 * @param {Object} meta Metadata configuration options
8426 * @param {Object} recordType Either an Array of field definition objects,
8427 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
8429 Roo.data.JsonReader = function(meta, recordType){
8432 // set some defaults:
8434 totalProperty: 'total',
8435 successProperty : 'success',
8440 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
8442 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
8445 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
8446 * Used by Store query builder to append _requestMeta to params.
8449 metaFromRemote : false,
8451 * This method is only used by a DataProxy which has retrieved data from a remote server.
8452 * @param {Object} response The XHR object which contains the JSON data in its responseText.
8453 * @return {Object} data A data block which is used by an Roo.data.Store object as
8454 * a cache of Roo.data.Records.
8456 read : function(response){
8457 var json = response.responseText;
8459 var o = /* eval:var:o */ eval("("+json+")");
8461 throw {message: "JsonReader.read: Json object not found"};
8467 this.metaFromRemote = true;
8468 this.meta = o.metaData;
8469 this.recordType = Roo.data.Record.create(o.metaData.fields);
8470 this.onMetaChange(this.meta, this.recordType, o);
8472 return this.readRecords(o);
8475 // private function a store will implement
8476 onMetaChange : function(meta, recordType, o){
8483 simpleAccess: function(obj, subsc) {
8490 getJsonAccessor: function(){
8492 return function(expr) {
8494 return(re.test(expr))
8495 ? new Function("obj", "return obj." + expr)
8505 * Create a data block containing Roo.data.Records from an XML document.
8506 * @param {Object} o An object which contains an Array of row objects in the property specified
8507 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
8508 * which contains the total size of the dataset.
8509 * @return {Object} data A data block which is used by an Roo.data.Store object as
8510 * a cache of Roo.data.Records.
8512 readRecords : function(o){
8514 * After any data loads, the raw JSON data is available for further custom processing.
8518 var s = this.meta, Record = this.recordType,
8519 f = Record.prototype.fields, fi = f.items, fl = f.length;
8521 // Generate extraction functions for the totalProperty, the root, the id, and for each field
8523 if(s.totalProperty) {
8524 this.getTotal = this.getJsonAccessor(s.totalProperty);
8526 if(s.successProperty) {
8527 this.getSuccess = this.getJsonAccessor(s.successProperty);
8529 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
8531 var g = this.getJsonAccessor(s.id);
8532 this.getId = function(rec) {
8534 return (r === undefined || r === "") ? null : r;
8537 this.getId = function(){return null;};
8540 for(var jj = 0; jj < fl; jj++){
8542 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
8543 this.ef[jj] = this.getJsonAccessor(map);
8547 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
8548 if(s.totalProperty){
8549 var vt = parseInt(this.getTotal(o), 10);
8554 if(s.successProperty){
8555 var vs = this.getSuccess(o);
8556 if(vs === false || vs === 'false'){
8561 for(var i = 0; i < c; i++){
8564 var id = this.getId(n);
8565 for(var j = 0; j < fl; j++){
8567 var v = this.ef[j](n);
8569 Roo.log('missing convert for ' + f.name);
8573 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
8575 var record = new Record(values, id);
8577 records[i] = record;
8583 totalRecords : totalRecords
8588 * Ext JS Library 1.1.1
8589 * Copyright(c) 2006-2007, Ext JS, LLC.
8591 * Originally Released Under LGPL - original licence link has changed is not relivant.
8594 * <script type="text/javascript">
8598 * @class Roo.data.ArrayReader
8599 * @extends Roo.data.DataReader
8600 * Data reader class to create an Array of Roo.data.Record objects from an Array.
8601 * Each element of that Array represents a row of data fields. The
8602 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
8603 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
8607 var RecordDef = Roo.data.Record.create([
8608 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
8609 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
8611 var myReader = new Roo.data.ArrayReader({
8612 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
8616 * This would consume an Array like this:
8618 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
8620 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
8622 * Create a new JsonReader
8623 * @param {Object} meta Metadata configuration options.
8624 * @param {Object} recordType Either an Array of field definition objects
8625 * as specified to {@link Roo.data.Record#create},
8626 * or an {@link Roo.data.Record} object
8627 * created using {@link Roo.data.Record#create}.
8629 Roo.data.ArrayReader = function(meta, recordType){
8630 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
8633 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
8635 * Create a data block containing Roo.data.Records from an XML document.
8636 * @param {Object} o An Array of row objects which represents the dataset.
8637 * @return {Object} data A data block which is used by an Roo.data.Store object as
8638 * a cache of Roo.data.Records.
8640 readRecords : function(o){
8641 var sid = this.meta ? this.meta.id : null;
8642 var recordType = this.recordType, fields = recordType.prototype.fields;
8645 for(var i = 0; i < root.length; i++){
8648 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
8649 for(var j = 0, jlen = fields.length; j < jlen; j++){
8650 var f = fields.items[j];
8651 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
8652 var v = n[k] !== undefined ? n[k] : f.defaultValue;
8656 var record = new recordType(values, id);
8658 records[records.length] = record;
8662 totalRecords : records.length
8671 * @class Roo.bootstrap.ComboBox
8672 * @extends Roo.bootstrap.TriggerField
8673 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
8674 * @cfg {Boolean} append (true|false) default false
8676 * Create a new ComboBox.
8677 * @param {Object} config Configuration options
8679 Roo.bootstrap.ComboBox = function(config){
8680 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
8684 * Fires when the dropdown list is expanded
8685 * @param {Roo.bootstrap.ComboBox} combo This combo box
8690 * Fires when the dropdown list is collapsed
8691 * @param {Roo.bootstrap.ComboBox} combo This combo box
8695 * @event beforeselect
8696 * Fires before a list item is selected. Return false to cancel the selection.
8697 * @param {Roo.bootstrap.ComboBox} combo This combo box
8698 * @param {Roo.data.Record} record The data record returned from the underlying store
8699 * @param {Number} index The index of the selected item in the dropdown list
8701 'beforeselect' : true,
8704 * Fires when a list item is selected
8705 * @param {Roo.bootstrap.ComboBox} combo This combo box
8706 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
8707 * @param {Number} index The index of the selected item in the dropdown list
8711 * @event beforequery
8712 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
8713 * The event object passed has these properties:
8714 * @param {Roo.bootstrap.ComboBox} combo This combo box
8715 * @param {String} query The query
8716 * @param {Boolean} forceAll true to force "all" query
8717 * @param {Boolean} cancel true to cancel the query
8718 * @param {Object} e The query event object
8720 'beforequery': true,
8723 * Fires when the 'add' icon is pressed (add a listener to enable add button)
8724 * @param {Roo.bootstrap.ComboBox} combo This combo box
8729 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
8730 * @param {Roo.bootstrap.ComboBox} combo This combo box
8731 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
8736 * Fires when the remove value from the combobox array
8737 * @param {Roo.bootstrap.ComboBox} combo This combo box
8744 this.selectedIndex = -1;
8745 if(this.mode == 'local'){
8746 if(config.queryDelay === undefined){
8747 this.queryDelay = 10;
8749 if(config.minChars === undefined){
8755 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
8758 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
8759 * rendering into an Roo.Editor, defaults to false)
8762 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
8763 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
8766 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
8769 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
8770 * the dropdown list (defaults to undefined, with no header element)
8774 * @cfg {String/Roo.Template} tpl The template to use to render the output
8778 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
8780 listWidth: undefined,
8782 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
8783 * mode = 'remote' or 'text' if mode = 'local')
8785 displayField: undefined,
8787 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
8788 * mode = 'remote' or 'value' if mode = 'local').
8789 * Note: use of a valueField requires the user make a selection
8790 * in order for a value to be mapped.
8792 valueField: undefined,
8796 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
8797 * field's data value (defaults to the underlying DOM element's name)
8799 hiddenName: undefined,
8801 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
8805 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
8807 selectedClass: 'active',
8810 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
8814 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
8815 * anchor positions (defaults to 'tl-bl')
8817 listAlign: 'tl-bl?',
8819 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
8823 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
8824 * query specified by the allQuery config option (defaults to 'query')
8826 triggerAction: 'query',
8828 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
8829 * (defaults to 4, does not apply if editable = false)
8833 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
8834 * delay (typeAheadDelay) if it matches a known value (defaults to false)
8838 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
8839 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
8843 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
8844 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
8848 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
8849 * when editable = true (defaults to false)
8851 selectOnFocus:false,
8853 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
8855 queryParam: 'query',
8857 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
8858 * when mode = 'remote' (defaults to 'Loading...')
8860 loadingText: 'Loading...',
8862 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
8866 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
8870 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
8871 * traditional select (defaults to true)
8875 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
8879 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
8883 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
8884 * listWidth has a higher value)
8888 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
8889 * allow the user to set arbitrary text into the field (defaults to false)
8891 forceSelection:false,
8893 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
8894 * if typeAhead = true (defaults to 250)
8896 typeAheadDelay : 250,
8898 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
8899 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
8901 valueNotFoundText : undefined,
8903 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
8908 * @cfg {Boolean} disableClear Disable showing of clear button.
8910 disableClear : false,
8912 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
8914 alwaysQuery : false,
8917 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
8931 // element that contains real text value.. (when hidden is used..)
8934 initEvents: function(){
8937 throw "can not find store for combo";
8939 this.store = Roo.factory(this.store, Roo.data);
8943 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
8946 if(this.hiddenName){
8948 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
8950 this.hiddenField.dom.value =
8951 this.hiddenValue !== undefined ? this.hiddenValue :
8952 this.value !== undefined ? this.value : '';
8954 // prevent input submission
8955 this.el.dom.removeAttribute('name');
8956 this.hiddenField.dom.setAttribute('name', this.hiddenName);
8961 // this.el.dom.setAttribute('autocomplete', 'off');
8964 var cls = 'x-combo-list';
8965 this.list = this.el.select('ul.dropdown-menu',true).first();
8967 //this.list = new Roo.Layer({
8968 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
8971 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
8972 this.list.setWidth(lw);
8974 this.list.on('mouseover', this.onViewOver, this);
8975 this.list.on('mousemove', this.onViewMove, this);
8977 this.list.on('scroll', this.onViewScroll, this);
8980 this.list.swallowEvent('mousewheel');
8981 this.assetHeight = 0;
8984 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
8985 this.assetHeight += this.header.getHeight();
8988 this.innerList = this.list.createChild({cls:cls+'-inner'});
8989 this.innerList.on('mouseover', this.onViewOver, this);
8990 this.innerList.on('mousemove', this.onViewMove, this);
8991 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
8993 if(this.allowBlank && !this.pageSize && !this.disableClear){
8994 this.footer = this.list.createChild({cls:cls+'-ft'});
8995 this.pageTb = new Roo.Toolbar(this.footer);
8999 this.footer = this.list.createChild({cls:cls+'-ft'});
9000 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
9001 {pageSize: this.pageSize});
9005 if (this.pageTb && this.allowBlank && !this.disableClear) {
9007 this.pageTb.add(new Roo.Toolbar.Fill(), {
9008 cls: 'x-btn-icon x-btn-clear',
9014 _this.onSelect(false, -1);
9019 this.assetHeight += this.footer.getHeight();
9024 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
9027 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
9028 singleSelect:true, store: this.store, selectedClass: this.selectedClass
9030 //this.view.wrapEl.setDisplayed(false);
9031 this.view.on('click', this.onViewClick, this);
9035 this.store.on('beforeload', this.onBeforeLoad, this);
9036 this.store.on('load', this.onLoad, this);
9037 this.store.on('loadexception', this.onLoadException, this);
9040 this.resizer = new Roo.Resizable(this.list, {
9041 pinned:true, handles:'se'
9043 this.resizer.on('resize', function(r, w, h){
9044 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
9046 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
9047 this.restrictHeight();
9049 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
9053 this.editable = true;
9054 this.setEditable(false);
9059 if (typeof(this.events.add.listeners) != 'undefined') {
9061 this.addicon = this.wrap.createChild(
9062 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
9064 this.addicon.on('click', function(e) {
9065 this.fireEvent('add', this);
9068 if (typeof(this.events.edit.listeners) != 'undefined') {
9070 this.editicon = this.wrap.createChild(
9071 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
9073 this.editicon.setStyle('margin-left', '40px');
9075 this.editicon.on('click', function(e) {
9077 // we fire even if inothing is selected..
9078 this.fireEvent('edit', this, this.lastData );
9084 this.keyNav = new Roo.KeyNav(this.inputEl(), {
9086 this.inKeyMode = true;
9090 "down" : function(e){
9091 if(!this.isExpanded()){
9092 this.onTriggerClick();
9094 this.inKeyMode = true;
9099 "enter" : function(e){
9104 "esc" : function(e){
9108 "tab" : function(e){
9111 if(this.fireEvent("specialkey", this, e)){
9112 this.onViewClick(false);
9120 doRelay : function(foo, bar, hname){
9121 if(hname == 'down' || this.scope.isExpanded()){
9122 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
9131 this.queryDelay = Math.max(this.queryDelay || 10,
9132 this.mode == 'local' ? 10 : 250);
9135 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
9138 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
9140 if(this.editable !== false){
9141 this.inputEl().on("keyup", this.onKeyUp, this);
9143 if(this.forceSelection){
9144 this.on('blur', this.doForce, this);
9148 this.choices = this.el.select('ul.select2-choices', true).first();
9149 this.searchField = this.el.select('ul li.select2-search-field', true).first();
9153 onDestroy : function(){
9155 this.view.setStore(null);
9156 this.view.el.removeAllListeners();
9157 this.view.el.remove();
9158 this.view.purgeListeners();
9161 this.list.dom.innerHTML = '';
9164 this.store.un('beforeload', this.onBeforeLoad, this);
9165 this.store.un('load', this.onLoad, this);
9166 this.store.un('loadexception', this.onLoadException, this);
9168 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
9172 fireKey : function(e){
9173 if(e.isNavKeyPress() && !this.list.isVisible()){
9174 this.fireEvent("specialkey", this, e);
9179 onResize: function(w, h){
9180 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
9182 // if(typeof w != 'number'){
9183 // // we do not handle it!?!?
9186 // var tw = this.trigger.getWidth();
9187 // // tw += this.addicon ? this.addicon.getWidth() : 0;
9188 // // tw += this.editicon ? this.editicon.getWidth() : 0;
9190 // this.inputEl().setWidth( this.adjustWidth('input', x));
9192 // //this.trigger.setStyle('left', x+'px');
9194 // if(this.list && this.listWidth === undefined){
9195 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
9196 // this.list.setWidth(lw);
9197 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
9205 * Allow or prevent the user from directly editing the field text. If false is passed,
9206 * the user will only be able to select from the items defined in the dropdown list. This method
9207 * is the runtime equivalent of setting the 'editable' config option at config time.
9208 * @param {Boolean} value True to allow the user to directly edit the field text
9210 setEditable : function(value){
9211 if(value == this.editable){
9214 this.editable = value;
9216 this.inputEl().dom.setAttribute('readOnly', true);
9217 this.inputEl().on('mousedown', this.onTriggerClick, this);
9218 this.inputEl().addClass('x-combo-noedit');
9220 this.inputEl().dom.setAttribute('readOnly', false);
9221 this.inputEl().un('mousedown', this.onTriggerClick, this);
9222 this.inputEl().removeClass('x-combo-noedit');
9228 onBeforeLoad : function(combo,opts){
9233 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
9235 this.restrictHeight();
9236 this.selectedIndex = -1;
9240 onLoad : function(){
9242 this.hasQuery = false;
9248 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
9249 this.loading.hide();
9252 if(this.store.getCount() > 0){
9254 this.restrictHeight();
9255 if(this.lastQuery == this.allQuery){
9257 this.inputEl().dom.select();
9259 if(!this.selectByValue(this.value, true)){
9260 this.select(0, true);
9264 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
9265 this.taTask.delay(this.typeAheadDelay);
9269 this.onEmptyResults();
9275 onLoadException : function()
9277 this.hasQuery = false;
9279 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
9280 this.loading.hide();
9284 Roo.log(this.store.reader.jsonData);
9285 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
9287 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
9293 onTypeAhead : function(){
9294 if(this.store.getCount() > 0){
9295 var r = this.store.getAt(0);
9296 var newValue = r.data[this.displayField];
9297 var len = newValue.length;
9298 var selStart = this.getRawValue().length;
9300 if(selStart != len){
9301 this.setRawValue(newValue);
9302 this.selectText(selStart, newValue.length);
9308 onSelect : function(record, index){
9310 if(this.fireEvent('beforeselect', this, record, index) !== false){
9312 this.setFromData(index > -1 ? record.data : false);
9315 this.fireEvent('select', this, record, index);
9320 * Returns the currently selected field value or empty string if no value is set.
9321 * @return {String} value The selected value
9323 getValue : function(){
9326 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
9329 if(this.valueField){
9330 return typeof this.value != 'undefined' ? this.value : '';
9332 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
9337 * Clears any text/value currently set in the field
9339 clearValue : function(){
9340 if(this.hiddenField){
9341 this.hiddenField.dom.value = '';
9344 this.setRawValue('');
9345 this.lastSelectionText = '';
9350 * Sets the specified value into the field. If the value finds a match, the corresponding record text
9351 * will be displayed in the field. If the value does not match the data value of an existing item,
9352 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
9353 * Otherwise the field will be blank (although the value will still be set).
9354 * @param {String} value The value to match
9356 setValue : function(v){
9363 if(this.valueField){
9364 var r = this.findRecord(this.valueField, v);
9366 text = r.data[this.displayField];
9367 }else if(this.valueNotFoundText !== undefined){
9368 text = this.valueNotFoundText;
9371 this.lastSelectionText = text;
9372 if(this.hiddenField){
9373 this.hiddenField.dom.value = v;
9375 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
9379 * @property {Object} the last set data for the element
9384 * Sets the value of the field based on a object which is related to the record format for the store.
9385 * @param {Object} value the value to set as. or false on reset?
9387 setFromData : function(o){
9394 var dv = ''; // display value
9395 var vv = ''; // value value..
9397 if (this.displayField) {
9398 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
9400 // this is an error condition!!!
9401 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
9404 if(this.valueField){
9405 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
9408 if(this.hiddenField){
9409 this.hiddenField.dom.value = vv;
9411 this.lastSelectionText = dv;
9412 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
9416 // no hidden field.. - we store the value in 'value', but still display
9417 // display field!!!!
9418 this.lastSelectionText = dv;
9419 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
9426 // overridden so that last data is reset..
9427 this.setValue(this.originalValue);
9428 this.clearInvalid();
9429 this.lastData = false;
9431 this.view.clearSelections();
9435 findRecord : function(prop, value){
9437 if(this.store.getCount() > 0){
9438 this.store.each(function(r){
9439 if(r.data[prop] == value){
9451 // returns hidden if it's set..
9452 if (!this.rendered) {return ''};
9453 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
9457 onViewMove : function(e, t){
9458 this.inKeyMode = false;
9462 onViewOver : function(e, t){
9463 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
9466 var item = this.view.findItemFromChild(t);
9468 var index = this.view.indexOf(item);
9469 this.select(index, false);
9474 onViewClick : function(doFocus)
9476 var index = this.view.getSelectedIndexes()[0];
9477 var r = this.store.getAt(index);
9479 this.onSelect(r, index);
9481 if(doFocus !== false && !this.blockFocus){
9482 this.inputEl().focus();
9487 restrictHeight : function(){
9488 //this.innerList.dom.style.height = '';
9489 //var inner = this.innerList.dom;
9490 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
9491 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
9492 //this.list.beginUpdate();
9493 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
9494 this.list.alignTo(this.inputEl(), this.listAlign);
9495 //this.list.endUpdate();
9499 onEmptyResults : function(){
9504 * Returns true if the dropdown list is expanded, else false.
9506 isExpanded : function(){
9507 return this.list.isVisible();
9511 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
9512 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
9513 * @param {String} value The data value of the item to select
9514 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
9515 * selected item if it is not currently in view (defaults to true)
9516 * @return {Boolean} True if the value matched an item in the list, else false
9518 selectByValue : function(v, scrollIntoView){
9519 if(v !== undefined && v !== null){
9520 var r = this.findRecord(this.valueField || this.displayField, v);
9522 this.select(this.store.indexOf(r), scrollIntoView);
9530 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
9531 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
9532 * @param {Number} index The zero-based index of the list item to select
9533 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
9534 * selected item if it is not currently in view (defaults to true)
9536 select : function(index, scrollIntoView){
9537 this.selectedIndex = index;
9538 this.view.select(index);
9539 if(scrollIntoView !== false){
9540 var el = this.view.getNode(index);
9542 //this.innerList.scrollChildIntoView(el, false);
9549 selectNext : function(){
9550 var ct = this.store.getCount();
9552 if(this.selectedIndex == -1){
9554 }else if(this.selectedIndex < ct-1){
9555 this.select(this.selectedIndex+1);
9561 selectPrev : function(){
9562 var ct = this.store.getCount();
9564 if(this.selectedIndex == -1){
9566 }else if(this.selectedIndex != 0){
9567 this.select(this.selectedIndex-1);
9573 onKeyUp : function(e){
9574 if(this.editable !== false && !e.isSpecialKey()){
9575 this.lastKey = e.getKey();
9576 this.dqTask.delay(this.queryDelay);
9581 validateBlur : function(){
9582 return !this.list || !this.list.isVisible();
9586 initQuery : function(){
9587 this.doQuery(this.getRawValue());
9591 doForce : function(){
9592 if(this.el.dom.value.length > 0){
9594 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
9600 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
9601 * query allowing the query action to be canceled if needed.
9602 * @param {String} query The SQL query to execute
9603 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
9604 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
9605 * saved in the current store (defaults to false)
9607 doQuery : function(q, forceAll){
9609 if(q === undefined || q === null){
9618 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
9623 forceAll = qe.forceAll;
9624 if(forceAll === true || (q.length >= this.minChars)){
9626 this.hasQuery = true;
9628 if(this.lastQuery != q || this.alwaysQuery){
9630 if(this.mode == 'local'){
9631 this.selectedIndex = -1;
9633 this.store.clearFilter();
9635 this.store.filter(this.displayField, q);
9639 this.store.baseParams[this.queryParam] = q;
9641 var options = {params : this.getParams(q)};
9645 options.params.start = this.page * this.pageSize;
9648 this.store.load(options);
9652 this.selectedIndex = -1;
9657 this.loadNext = false;
9661 getParams : function(q){
9663 //p[this.queryParam] = q;
9667 p.limit = this.pageSize;
9673 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
9675 collapse : function(){
9676 if(!this.isExpanded()){
9681 Roo.get(document).un('mousedown', this.collapseIf, this);
9682 Roo.get(document).un('mousewheel', this.collapseIf, this);
9683 if (!this.editable) {
9684 Roo.get(document).un('keydown', this.listKeyPress, this);
9686 this.fireEvent('collapse', this);
9690 collapseIf : function(e){
9691 var in_combo = e.within(this.el);
9692 var in_list = e.within(this.list);
9694 if (in_combo || in_list) {
9695 //e.stopPropagation();
9704 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
9706 expand : function(){
9708 if(this.isExpanded() || !this.hasFocus){
9712 this.list.alignTo(this.inputEl(), this.listAlign);
9714 Roo.get(document).on('mousedown', this.collapseIf, this);
9715 Roo.get(document).on('mousewheel', this.collapseIf, this);
9716 if (!this.editable) {
9717 Roo.get(document).on('keydown', this.listKeyPress, this);
9720 this.fireEvent('expand', this);
9724 // Implements the default empty TriggerField.onTriggerClick function
9725 onTriggerClick : function()
9727 Roo.log('trigger click');
9734 this.loadNext = false;
9736 if(this.isExpanded()){
9738 if (!this.blockFocus) {
9739 this.inputEl().focus();
9743 this.hasFocus = true;
9744 if(this.triggerAction == 'all') {
9745 this.doQuery(this.allQuery, true);
9747 this.doQuery(this.getRawValue());
9749 if (!this.blockFocus) {
9750 this.inputEl().focus();
9754 listKeyPress : function(e)
9756 //Roo.log('listkeypress');
9757 // scroll to first matching element based on key pres..
9758 if (e.isSpecialKey()) {
9761 var k = String.fromCharCode(e.getKey()).toUpperCase();
9764 var csel = this.view.getSelectedNodes();
9765 var cselitem = false;
9767 var ix = this.view.indexOf(csel[0]);
9768 cselitem = this.store.getAt(ix);
9769 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
9775 this.store.each(function(v) {
9777 // start at existing selection.
9778 if (cselitem.id == v.id) {
9784 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
9785 match = this.store.indexOf(v);
9791 if (match === false) {
9792 return true; // no more action?
9795 this.view.select(match);
9796 var sn = Roo.get(this.view.getSelectedNodes()[0])
9797 //sn.scrollIntoView(sn.dom.parentNode, false);
9800 onViewScroll : function(e, t){
9802 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
9806 this.hasQuery = true;
9808 this.loading = this.list.select('.loading', true).first();
9810 if(this.loading === null){
9811 this.list.createChild({
9813 cls: 'loading select2-more-results select2-active',
9814 html: 'Loading more results...'
9817 this.loading = this.list.select('.loading', true).first();
9819 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
9821 this.loading.hide();
9824 this.loading.show();
9829 this.loadNext = true;
9831 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
9836 addItem : function(o)
9838 var dv = ''; // display value
9840 if (this.displayField) {
9841 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
9843 // this is an error condition!!!
9844 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
9851 var choice = this.choices.createChild({
9853 cls: 'select2-search-choice',
9862 cls: 'select2-search-choice-close',
9867 }, this.searchField);
9869 var close = choice.select('a.select2-search-choice-close', true).first()
9871 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
9878 this.inputEl().dom.value = '';
9882 onRemoveItem : function(e, _self, o)
9884 Roo.log('remove item');
9885 var index = this.item.indexOf(o.data) * 1;
9888 Roo.log('not this item?!');
9892 this.item.splice(index, 1);
9897 this.fireEvent('remove', this);
9901 syncValue : function()
9903 if(!this.item.length){
9910 Roo.each(this.item, function(i){
9911 if(_this.valueField){
9912 value.push(i[_this.valueField]);
9919 this.value = value.join(',');
9921 if(this.hiddenField){
9922 this.hiddenField.dom.value = this.value;
9926 clearItem : function()
9934 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
9944 * @cfg {Boolean} grow
9948 * @cfg {Number} growMin
9952 * @cfg {Number} growMax
9962 * Ext JS Library 1.1.1
9963 * Copyright(c) 2006-2007, Ext JS, LLC.
9965 * Originally Released Under LGPL - original licence link has changed is not relivant.
9968 * <script type="text/javascript">
9973 * @extends Roo.util.Observable
9974 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
9975 * This class also supports single and multi selection modes. <br>
9976 * Create a data model bound view:
9978 var store = new Roo.data.Store(...);
9980 var view = new Roo.View({
9982 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
9985 selectedClass: "ydataview-selected",
9989 // listen for node click?
9990 view.on("click", function(vw, index, node, e){
9991 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9995 dataModel.load("foobar.xml");
9997 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
9999 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
10000 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
10002 * Note: old style constructor is still suported (container, template, config)
10005 * Create a new View
10006 * @param {Object} config The config object
10009 Roo.View = function(config, depreciated_tpl, depreciated_config){
10011 if (typeof(depreciated_tpl) == 'undefined') {
10012 // new way.. - universal constructor.
10013 Roo.apply(this, config);
10014 this.el = Roo.get(this.el);
10017 this.el = Roo.get(config);
10018 this.tpl = depreciated_tpl;
10019 Roo.apply(this, depreciated_config);
10021 this.wrapEl = this.el.wrap().wrap();
10022 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
10025 if(typeof(this.tpl) == "string"){
10026 this.tpl = new Roo.Template(this.tpl);
10028 // support xtype ctors..
10029 this.tpl = new Roo.factory(this.tpl, Roo);
10033 this.tpl.compile();
10041 * @event beforeclick
10042 * Fires before a click is processed. Returns false to cancel the default action.
10043 * @param {Roo.View} this
10044 * @param {Number} index The index of the target node
10045 * @param {HTMLElement} node The target node
10046 * @param {Roo.EventObject} e The raw event object
10048 "beforeclick" : true,
10051 * Fires when a template node is clicked.
10052 * @param {Roo.View} this
10053 * @param {Number} index The index of the target node
10054 * @param {HTMLElement} node The target node
10055 * @param {Roo.EventObject} e The raw event object
10060 * Fires when a template node is double clicked.
10061 * @param {Roo.View} this
10062 * @param {Number} index The index of the target node
10063 * @param {HTMLElement} node The target node
10064 * @param {Roo.EventObject} e The raw event object
10068 * @event contextmenu
10069 * Fires when a template node is right clicked.
10070 * @param {Roo.View} this
10071 * @param {Number} index The index of the target node
10072 * @param {HTMLElement} node The target node
10073 * @param {Roo.EventObject} e The raw event object
10075 "contextmenu" : true,
10077 * @event selectionchange
10078 * Fires when the selected nodes change.
10079 * @param {Roo.View} this
10080 * @param {Array} selections Array of the selected nodes
10082 "selectionchange" : true,
10085 * @event beforeselect
10086 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
10087 * @param {Roo.View} this
10088 * @param {HTMLElement} node The node to be selected
10089 * @param {Array} selections Array of currently selected nodes
10091 "beforeselect" : true,
10093 * @event preparedata
10094 * Fires on every row to render, to allow you to change the data.
10095 * @param {Roo.View} this
10096 * @param {Object} data to be rendered (change this)
10098 "preparedata" : true
10106 "click": this.onClick,
10107 "dblclick": this.onDblClick,
10108 "contextmenu": this.onContextMenu,
10112 this.selections = [];
10114 this.cmp = new Roo.CompositeElementLite([]);
10116 this.store = Roo.factory(this.store, Roo.data);
10117 this.setStore(this.store, true);
10120 if ( this.footer && this.footer.xtype) {
10122 var fctr = this.wrapEl.appendChild(document.createElement("div"));
10124 this.footer.dataSource = this.store
10125 this.footer.container = fctr;
10126 this.footer = Roo.factory(this.footer, Roo);
10127 fctr.insertFirst(this.el);
10129 // this is a bit insane - as the paging toolbar seems to detach the el..
10130 // dom.parentNode.parentNode.parentNode
10131 // they get detached?
10135 Roo.View.superclass.constructor.call(this);
10140 Roo.extend(Roo.View, Roo.util.Observable, {
10143 * @cfg {Roo.data.Store} store Data store to load data from.
10148 * @cfg {String|Roo.Element} el The container element.
10153 * @cfg {String|Roo.Template} tpl The template used by this View
10157 * @cfg {String} dataName the named area of the template to use as the data area
10158 * Works with domtemplates roo-name="name"
10162 * @cfg {String} selectedClass The css class to add to selected nodes
10164 selectedClass : "x-view-selected",
10166 * @cfg {String} emptyText The empty text to show when nothing is loaded.
10171 * @cfg {String} text to display on mask (default Loading)
10175 * @cfg {Boolean} multiSelect Allow multiple selection
10177 multiSelect : false,
10179 * @cfg {Boolean} singleSelect Allow single selection
10181 singleSelect: false,
10184 * @cfg {Boolean} toggleSelect - selecting
10186 toggleSelect : false,
10189 * Returns the element this view is bound to.
10190 * @return {Roo.Element}
10192 getEl : function(){
10193 return this.wrapEl;
10199 * Refreshes the view. - called by datachanged on the store. - do not call directly.
10201 refresh : function(){
10202 Roo.log('refresh');
10205 // if we are using something like 'domtemplate', then
10206 // the what gets used is:
10207 // t.applySubtemplate(NAME, data, wrapping data..)
10208 // the outer template then get' applied with
10209 // the store 'extra data'
10210 // and the body get's added to the
10211 // roo-name="data" node?
10212 // <span class='roo-tpl-{name}'></span> ?????
10216 this.clearSelections();
10217 this.el.update("");
10219 var records = this.store.getRange();
10220 if(records.length < 1) {
10222 // is this valid?? = should it render a template??
10224 this.el.update(this.emptyText);
10228 if (this.dataName) {
10229 this.el.update(t.apply(this.store.meta)); //????
10230 el = this.el.child('.roo-tpl-' + this.dataName);
10233 for(var i = 0, len = records.length; i < len; i++){
10234 var data = this.prepareData(records[i].data, i, records[i]);
10235 this.fireEvent("preparedata", this, data, i, records[i]);
10236 html[html.length] = Roo.util.Format.trim(
10238 t.applySubtemplate(this.dataName, data, this.store.meta) :
10245 el.update(html.join(""));
10246 this.nodes = el.dom.childNodes;
10247 this.updateIndexes(0);
10252 * Function to override to reformat the data that is sent to
10253 * the template for each node.
10254 * DEPRICATED - use the preparedata event handler.
10255 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
10256 * a JSON object for an UpdateManager bound view).
10258 prepareData : function(data, index, record)
10260 this.fireEvent("preparedata", this, data, index, record);
10264 onUpdate : function(ds, record){
10265 Roo.log('on update');
10266 this.clearSelections();
10267 var index = this.store.indexOf(record);
10268 var n = this.nodes[index];
10269 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
10270 n.parentNode.removeChild(n);
10271 this.updateIndexes(index, index);
10277 onAdd : function(ds, records, index)
10279 Roo.log(['on Add', ds, records, index] );
10280 this.clearSelections();
10281 if(this.nodes.length == 0){
10285 var n = this.nodes[index];
10286 for(var i = 0, len = records.length; i < len; i++){
10287 var d = this.prepareData(records[i].data, i, records[i]);
10289 this.tpl.insertBefore(n, d);
10292 this.tpl.append(this.el, d);
10295 this.updateIndexes(index);
10298 onRemove : function(ds, record, index){
10299 Roo.log('onRemove');
10300 this.clearSelections();
10301 var el = this.dataName ?
10302 this.el.child('.roo-tpl-' + this.dataName) :
10305 el.dom.removeChild(this.nodes[index]);
10306 this.updateIndexes(index);
10310 * Refresh an individual node.
10311 * @param {Number} index
10313 refreshNode : function(index){
10314 this.onUpdate(this.store, this.store.getAt(index));
10317 updateIndexes : function(startIndex, endIndex){
10318 var ns = this.nodes;
10319 startIndex = startIndex || 0;
10320 endIndex = endIndex || ns.length - 1;
10321 for(var i = startIndex; i <= endIndex; i++){
10322 ns[i].nodeIndex = i;
10327 * Changes the data store this view uses and refresh the view.
10328 * @param {Store} store
10330 setStore : function(store, initial){
10331 if(!initial && this.store){
10332 this.store.un("datachanged", this.refresh);
10333 this.store.un("add", this.onAdd);
10334 this.store.un("remove", this.onRemove);
10335 this.store.un("update", this.onUpdate);
10336 this.store.un("clear", this.refresh);
10337 this.store.un("beforeload", this.onBeforeLoad);
10338 this.store.un("load", this.onLoad);
10339 this.store.un("loadexception", this.onLoad);
10343 store.on("datachanged", this.refresh, this);
10344 store.on("add", this.onAdd, this);
10345 store.on("remove", this.onRemove, this);
10346 store.on("update", this.onUpdate, this);
10347 store.on("clear", this.refresh, this);
10348 store.on("beforeload", this.onBeforeLoad, this);
10349 store.on("load", this.onLoad, this);
10350 store.on("loadexception", this.onLoad, this);
10358 * onbeforeLoad - masks the loading area.
10361 onBeforeLoad : function(store,opts)
10363 Roo.log('onBeforeLoad');
10365 this.el.update("");
10367 this.el.mask(this.mask ? this.mask : "Loading" );
10369 onLoad : function ()
10376 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
10377 * @param {HTMLElement} node
10378 * @return {HTMLElement} The template node
10380 findItemFromChild : function(node){
10381 var el = this.dataName ?
10382 this.el.child('.roo-tpl-' + this.dataName,true) :
10385 if(!node || node.parentNode == el){
10388 var p = node.parentNode;
10389 while(p && p != el){
10390 if(p.parentNode == el){
10399 onClick : function(e){
10400 var item = this.findItemFromChild(e.getTarget());
10402 var index = this.indexOf(item);
10403 if(this.onItemClick(item, index, e) !== false){
10404 this.fireEvent("click", this, index, item, e);
10407 this.clearSelections();
10412 onContextMenu : function(e){
10413 var item = this.findItemFromChild(e.getTarget());
10415 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
10420 onDblClick : function(e){
10421 var item = this.findItemFromChild(e.getTarget());
10423 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
10427 onItemClick : function(item, index, e)
10429 if(this.fireEvent("beforeclick", this, index, item, e) === false){
10432 if (this.toggleSelect) {
10433 var m = this.isSelected(item) ? 'unselect' : 'select';
10436 _t[m](item, true, false);
10439 if(this.multiSelect || this.singleSelect){
10440 if(this.multiSelect && e.shiftKey && this.lastSelection){
10441 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
10443 this.select(item, this.multiSelect && e.ctrlKey);
10444 this.lastSelection = item;
10446 e.preventDefault();
10452 * Get the number of selected nodes.
10455 getSelectionCount : function(){
10456 return this.selections.length;
10460 * Get the currently selected nodes.
10461 * @return {Array} An array of HTMLElements
10463 getSelectedNodes : function(){
10464 return this.selections;
10468 * Get the indexes of the selected nodes.
10471 getSelectedIndexes : function(){
10472 var indexes = [], s = this.selections;
10473 for(var i = 0, len = s.length; i < len; i++){
10474 indexes.push(s[i].nodeIndex);
10480 * Clear all selections
10481 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
10483 clearSelections : function(suppressEvent){
10484 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
10485 this.cmp.elements = this.selections;
10486 this.cmp.removeClass(this.selectedClass);
10487 this.selections = [];
10488 if(!suppressEvent){
10489 this.fireEvent("selectionchange", this, this.selections);
10495 * Returns true if the passed node is selected
10496 * @param {HTMLElement/Number} node The node or node index
10497 * @return {Boolean}
10499 isSelected : function(node){
10500 var s = this.selections;
10504 node = this.getNode(node);
10505 return s.indexOf(node) !== -1;
10510 * @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
10511 * @param {Boolean} keepExisting (optional) true to keep existing selections
10512 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
10514 select : function(nodeInfo, keepExisting, suppressEvent){
10515 if(nodeInfo instanceof Array){
10517 this.clearSelections(true);
10519 for(var i = 0, len = nodeInfo.length; i < len; i++){
10520 this.select(nodeInfo[i], true, true);
10524 var node = this.getNode(nodeInfo);
10525 if(!node || this.isSelected(node)){
10526 return; // already selected.
10529 this.clearSelections(true);
10531 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
10532 Roo.fly(node).addClass(this.selectedClass);
10533 this.selections.push(node);
10534 if(!suppressEvent){
10535 this.fireEvent("selectionchange", this, this.selections);
10543 * @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
10544 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
10545 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
10547 unselect : function(nodeInfo, keepExisting, suppressEvent)
10549 if(nodeInfo instanceof Array){
10550 Roo.each(this.selections, function(s) {
10551 this.unselect(s, nodeInfo);
10555 var node = this.getNode(nodeInfo);
10556 if(!node || !this.isSelected(node)){
10557 Roo.log("not selected");
10558 return; // not selected.
10562 Roo.each(this.selections, function(s) {
10564 Roo.fly(node).removeClass(this.selectedClass);
10571 this.selections= ns;
10572 this.fireEvent("selectionchange", this, this.selections);
10576 * Gets a template node.
10577 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
10578 * @return {HTMLElement} The node or null if it wasn't found
10580 getNode : function(nodeInfo){
10581 if(typeof nodeInfo == "string"){
10582 return document.getElementById(nodeInfo);
10583 }else if(typeof nodeInfo == "number"){
10584 return this.nodes[nodeInfo];
10590 * Gets a range template nodes.
10591 * @param {Number} startIndex
10592 * @param {Number} endIndex
10593 * @return {Array} An array of nodes
10595 getNodes : function(start, end){
10596 var ns = this.nodes;
10597 start = start || 0;
10598 end = typeof end == "undefined" ? ns.length - 1 : end;
10601 for(var i = start; i <= end; i++){
10605 for(var i = start; i >= end; i--){
10613 * Finds the index of the passed node
10614 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
10615 * @return {Number} The index of the node or -1
10617 indexOf : function(node){
10618 node = this.getNode(node);
10619 if(typeof node.nodeIndex == "number"){
10620 return node.nodeIndex;
10622 var ns = this.nodes;
10623 for(var i = 0, len = ns.length; i < len; i++){
10634 * based on jquery fullcalendar
10638 Roo.bootstrap = Roo.bootstrap || {};
10640 * @class Roo.bootstrap.Calendar
10641 * @extends Roo.bootstrap.Component
10642 * Bootstrap Calendar class
10643 * @cfg {Boolean} loadMask (true|false) default false
10644 * @cfg {Object} header generate the user specific header of the calendar, default false
10647 * Create a new Container
10648 * @param {Object} config The config object
10653 Roo.bootstrap.Calendar = function(config){
10654 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
10658 * Fires when a date is selected
10659 * @param {DatePicker} this
10660 * @param {Date} date The selected date
10664 * @event monthchange
10665 * Fires when the displayed month changes
10666 * @param {DatePicker} this
10667 * @param {Date} date The selected month
10669 'monthchange': true,
10671 * @event evententer
10672 * Fires when mouse over an event
10673 * @param {Calendar} this
10674 * @param {event} Event
10676 'evententer': true,
10678 * @event eventleave
10679 * Fires when the mouse leaves an
10680 * @param {Calendar} this
10683 'eventleave': true,
10685 * @event eventclick
10686 * Fires when the mouse click an
10687 * @param {Calendar} this
10696 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
10699 * @cfg {Number} startDay
10700 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
10708 getAutoCreate : function(){
10711 var fc_button = function(name, corner, style, content ) {
10712 return Roo.apply({},{
10714 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
10716 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
10719 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
10730 style : 'width:100%',
10737 cls : 'fc-header-left',
10739 fc_button('prev', 'left', 'arrow', '‹' ),
10740 fc_button('next', 'right', 'arrow', '›' ),
10741 { tag: 'span', cls: 'fc-header-space' },
10742 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
10750 cls : 'fc-header-center',
10754 cls: 'fc-header-title',
10757 html : 'month / year'
10765 cls : 'fc-header-right',
10767 /* fc_button('month', 'left', '', 'month' ),
10768 fc_button('week', '', '', 'week' ),
10769 fc_button('day', 'right', '', 'day' )
10781 header = this.header;
10784 var cal_heads = function() {
10786 // fixme - handle this.
10788 for (var i =0; i < Date.dayNames.length; i++) {
10789 var d = Date.dayNames[i];
10792 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
10793 html : d.substring(0,3)
10797 ret[0].cls += ' fc-first';
10798 ret[6].cls += ' fc-last';
10801 var cal_cell = function(n) {
10804 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
10809 cls: 'fc-day-number',
10813 cls: 'fc-day-content',
10817 style: 'position: relative;' // height: 17px;
10829 var cal_rows = function() {
10832 for (var r = 0; r < 6; r++) {
10839 for (var i =0; i < Date.dayNames.length; i++) {
10840 var d = Date.dayNames[i];
10841 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
10844 row.cn[0].cls+=' fc-first';
10845 row.cn[0].cn[0].style = 'min-height:90px';
10846 row.cn[6].cls+=' fc-last';
10850 ret[0].cls += ' fc-first';
10851 ret[4].cls += ' fc-prev-last';
10852 ret[5].cls += ' fc-last';
10859 cls: 'fc-border-separate',
10860 style : 'width:100%',
10868 cls : 'fc-first fc-last',
10886 cls : 'fc-content',
10887 style : "position: relative;",
10890 cls : 'fc-view fc-view-month fc-grid',
10891 style : 'position: relative',
10892 unselectable : 'on',
10895 cls : 'fc-event-container',
10896 style : 'position:absolute;z-index:8;top:0;left:0;'
10914 initEvents : function()
10917 throw "can not find store for calendar";
10923 style: "text-align:center",
10927 style: "background-color:white;width:50%;margin:250 auto",
10931 src: rootURL + '/roojs1/images/ux/lightbox/loading.gif'
10942 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
10944 var size = this.el.select('.fc-content', true).first().getSize();
10945 this.maskEl.setSize(size.width, size.height);
10946 this.maskEl.enableDisplayMode("block");
10947 if(!this.loadMask){
10948 this.maskEl.hide();
10951 this.store = Roo.factory(this.store, Roo.data);
10952 this.store.on('load', this.onLoad, this);
10953 this.store.on('beforeload', this.onBeforeLoad, this);
10957 this.cells = this.el.select('.fc-day',true);
10958 //Roo.log(this.cells);
10959 this.textNodes = this.el.query('.fc-day-number');
10960 this.cells.addClassOnOver('fc-state-hover');
10962 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
10963 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
10964 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
10965 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
10967 this.on('monthchange', this.onMonthChange, this);
10969 this.update(new Date().clearTime());
10972 resize : function() {
10973 var sz = this.el.getSize();
10975 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
10976 this.el.select('.fc-day-content div',true).setHeight(34);
10981 showPrevMonth : function(e){
10982 this.update(this.activeDate.add("mo", -1));
10984 showToday : function(e){
10985 this.update(new Date().clearTime());
10988 showNextMonth : function(e){
10989 this.update(this.activeDate.add("mo", 1));
10993 showPrevYear : function(){
10994 this.update(this.activeDate.add("y", -1));
10998 showNextYear : function(){
10999 this.update(this.activeDate.add("y", 1));
11004 update : function(date)
11006 var vd = this.activeDate;
11007 this.activeDate = date;
11008 // if(vd && this.el){
11009 // var t = date.getTime();
11010 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
11011 // Roo.log('using add remove');
11013 // this.fireEvent('monthchange', this, date);
11015 // this.cells.removeClass("fc-state-highlight");
11016 // this.cells.each(function(c){
11017 // if(c.dateValue == t){
11018 // c.addClass("fc-state-highlight");
11019 // setTimeout(function(){
11020 // try{c.dom.firstChild.focus();}catch(e){}
11030 var days = date.getDaysInMonth();
11032 var firstOfMonth = date.getFirstDateOfMonth();
11033 var startingPos = firstOfMonth.getDay()-this.startDay;
11035 if(startingPos < this.startDay){
11039 var pm = date.add(Date.MONTH, -1);
11040 var prevStart = pm.getDaysInMonth()-startingPos;
11042 this.cells = this.el.select('.fc-day',true);
11043 this.textNodes = this.el.query('.fc-day-number');
11044 this.cells.addClassOnOver('fc-state-hover');
11046 var cells = this.cells.elements;
11047 var textEls = this.textNodes;
11049 Roo.each(cells, function(cell){
11050 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
11053 days += startingPos;
11055 // convert everything to numbers so it's fast
11056 var day = 86400000;
11057 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
11060 //Roo.log(prevStart);
11062 var today = new Date().clearTime().getTime();
11063 var sel = date.clearTime().getTime();
11064 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
11065 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
11066 var ddMatch = this.disabledDatesRE;
11067 var ddText = this.disabledDatesText;
11068 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
11069 var ddaysText = this.disabledDaysText;
11070 var format = this.format;
11072 var setCellClass = function(cal, cell){
11074 //Roo.log('set Cell Class');
11076 var t = d.getTime();
11080 cell.dateValue = t;
11082 cell.className += " fc-today";
11083 cell.className += " fc-state-highlight";
11084 cell.title = cal.todayText;
11087 // disable highlight in other month..
11088 //cell.className += " fc-state-highlight";
11093 cell.className = " fc-state-disabled";
11094 cell.title = cal.minText;
11098 cell.className = " fc-state-disabled";
11099 cell.title = cal.maxText;
11103 if(ddays.indexOf(d.getDay()) != -1){
11104 cell.title = ddaysText;
11105 cell.className = " fc-state-disabled";
11108 if(ddMatch && format){
11109 var fvalue = d.dateFormat(format);
11110 if(ddMatch.test(fvalue)){
11111 cell.title = ddText.replace("%0", fvalue);
11112 cell.className = " fc-state-disabled";
11116 if (!cell.initialClassName) {
11117 cell.initialClassName = cell.dom.className;
11120 cell.dom.className = cell.initialClassName + ' ' + cell.className;
11125 for(; i < startingPos; i++) {
11126 textEls[i].innerHTML = (++prevStart);
11127 d.setDate(d.getDate()+1);
11129 cells[i].className = "fc-past fc-other-month";
11130 setCellClass(this, cells[i]);
11135 for(; i < days; i++){
11136 intDay = i - startingPos + 1;
11137 textEls[i].innerHTML = (intDay);
11138 d.setDate(d.getDate()+1);
11140 cells[i].className = ''; // "x-date-active";
11141 setCellClass(this, cells[i]);
11145 for(; i < 42; i++) {
11146 textEls[i].innerHTML = (++extraDays);
11147 d.setDate(d.getDate()+1);
11149 cells[i].className = "fc-future fc-other-month";
11150 setCellClass(this, cells[i]);
11153 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
11155 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
11157 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
11158 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
11160 if(totalRows != 6){
11161 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
11162 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
11165 this.fireEvent('monthchange', this, date);
11169 if(!this.internalRender){
11170 var main = this.el.dom.firstChild;
11171 var w = main.offsetWidth;
11172 this.el.setWidth(w + this.el.getBorderWidth("lr"));
11173 Roo.fly(main).setWidth(w);
11174 this.internalRender = true;
11175 // opera does not respect the auto grow header center column
11176 // then, after it gets a width opera refuses to recalculate
11177 // without a second pass
11178 if(Roo.isOpera && !this.secondPass){
11179 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
11180 this.secondPass = true;
11181 this.update.defer(10, this, [date]);
11188 findCell : function(dt) {
11189 dt = dt.clearTime().getTime();
11191 this.cells.each(function(c){
11192 //Roo.log("check " +c.dateValue + '?=' + dt);
11193 if(c.dateValue == dt){
11203 findCells : function(ev) {
11204 var s = ev.start.clone().clearTime().getTime();
11206 var e= ev.end.clone().clearTime().getTime();
11209 this.cells.each(function(c){
11210 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
11212 if(c.dateValue > e){
11215 if(c.dateValue < s){
11224 findBestRow: function(cells)
11228 for (var i =0 ; i < cells.length;i++) {
11229 ret = Math.max(cells[i].rows || 0,ret);
11236 addItem : function(ev)
11238 // look for vertical location slot in
11239 var cells = this.findCells(ev);
11241 ev.row = this.findBestRow(cells);
11243 // work out the location.
11247 for(var i =0; i < cells.length; i++) {
11255 if (crow.start.getY() == cells[i].getY()) {
11257 crow.end = cells[i];
11273 for (var i = 0; i < cells.length;i++) {
11274 cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
11278 this.calevents.push(ev);
11281 clearEvents: function() {
11283 if(!this.calevents){
11287 Roo.each(this.cells.elements, function(c){
11291 Roo.each(this.calevents, function(e) {
11292 Roo.each(e.els, function(el) {
11293 el.un('mouseenter' ,this.onEventEnter, this);
11294 el.un('mouseleave' ,this.onEventLeave, this);
11301 renderEvents: function()
11303 // first make sure there is enough space..
11305 this.cells.each(function(c) {
11307 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.rows * 20));
11310 for (var e = 0; e < this.calevents.length; e++) {
11311 var ev = this.calevents[e];
11312 var cells = ev.cells;
11313 var rows = ev.rows;
11315 for(var i =0; i < rows.length; i++) {
11318 // how many rows should it span..
11321 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
11322 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
11324 unselectable : "on",
11327 cls: 'fc-event-inner',
11331 // cls: 'fc-event-time',
11332 // html : cells.length > 1 ? '' : ev.time
11336 cls: 'fc-event-title',
11337 html : String.format('{0}', ev.title)
11344 cls: 'ui-resizable-handle ui-resizable-e',
11345 html : '  '
11351 cfg.cls += ' fc-event-start';
11353 if ((i+1) == rows.length) {
11354 cfg.cls += ' fc-event-end';
11357 var ctr = this.el.select('.fc-event-container',true).first();
11358 var cg = ctr.createChild(cfg);
11360 cg.on('mouseenter' ,this.onEventEnter, this, ev);
11361 cg.on('mouseleave' ,this.onEventLeave, this, ev);
11362 cg.on('click', this.onEventClick, this, ev);
11366 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
11367 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
11369 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
11370 cg.setWidth(ebox.right - sbox.x -2);
11378 onEventEnter: function (e, el,event,d) {
11379 this.fireEvent('evententer', this, el, event);
11382 onEventLeave: function (e, el,event,d) {
11383 this.fireEvent('eventleave', this, el, event);
11386 onEventClick: function (e, el,event,d) {
11387 this.fireEvent('eventclick', this, el, event);
11390 onMonthChange: function () {
11394 onLoad: function ()
11396 this.calevents = [];
11399 if(this.store.getCount() > 0){
11400 this.store.data.each(function(d){
11403 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
11404 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
11405 time : d.data.start_time,
11406 title : d.data.title,
11407 description : d.data.description,
11408 venue : d.data.venue
11413 this.renderEvents();
11416 this.maskEl.hide();
11420 onBeforeLoad: function()
11422 this.clearEvents();
11425 this.maskEl.show();
11439 * @class Roo.bootstrap.Popover
11440 * @extends Roo.bootstrap.Component
11441 * Bootstrap Popover class
11442 * @cfg {String} html contents of the popover (or false to use children..)
11443 * @cfg {String} title of popover (or false to hide)
11444 * @cfg {String} placement how it is placed
11445 * @cfg {String} trigger click || hover (or false to trigger manually)
11446 * @cfg {String} over what (parent or false to trigger manually.)
11449 * Create a new Popover
11450 * @param {Object} config The config object
11453 Roo.bootstrap.Popover = function(config){
11454 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
11457 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
11459 title: 'Fill in a title',
11462 placement : 'right',
11463 trigger : 'hover', // hover
11467 can_build_overlaid : false,
11469 getChildContainer : function()
11471 return this.el.select('.popover-content',true).first();
11474 getAutoCreate : function(){
11475 Roo.log('make popover?');
11477 cls : 'popover roo-dynamic',
11478 style: 'display:block',
11484 cls : 'popover-inner',
11488 cls: 'popover-title',
11492 cls : 'popover-content',
11503 setTitle: function(str)
11505 this.el.select('.popover-title',true).first().dom.innerHTML = str;
11507 setContent: function(str)
11509 this.el.select('.popover-content',true).first().dom.innerHTML = str;
11511 // as it get's added to the bottom of the page.
11512 onRender : function(ct, position)
11514 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
11516 var cfg = Roo.apply({}, this.getAutoCreate());
11520 cfg.cls += ' ' + this.cls;
11523 cfg.style = this.style;
11525 Roo.log("adding to ")
11526 this.el = Roo.get(document.body).createChild(cfg, position);
11532 initEvents : function()
11534 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
11535 this.el.enableDisplayMode('block');
11537 if (this.over === false) {
11540 if (this.triggers === false) {
11543 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
11544 var triggers = this.trigger ? this.trigger.split(' ') : [];
11545 Roo.each(triggers, function(trigger) {
11547 if (trigger == 'click') {
11548 on_el.on('click', this.toggle, this);
11549 } else if (trigger != 'manual') {
11550 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
11551 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
11553 on_el.on(eventIn ,this.enter, this);
11554 on_el.on(eventOut, this.leave, this);
11565 toggle : function () {
11566 this.hoverState == 'in' ? this.leave() : this.enter();
11569 enter : function () {
11572 clearTimeout(this.timeout);
11574 this.hoverState = 'in'
11576 if (!this.delay || !this.delay.show) {
11581 this.timeout = setTimeout(function () {
11582 if (_t.hoverState == 'in') {
11585 }, this.delay.show)
11587 leave : function() {
11588 clearTimeout(this.timeout);
11590 this.hoverState = 'out'
11592 if (!this.delay || !this.delay.hide) {
11597 this.timeout = setTimeout(function () {
11598 if (_t.hoverState == 'out') {
11601 }, this.delay.hide)
11604 show : function (on_el)
11607 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
11610 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
11611 if (this.html !== false) {
11612 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
11614 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
11615 if (!this.title.length) {
11616 this.el.select('.popover-title',true).hide();
11619 var placement = typeof this.placement == 'function' ?
11620 this.placement.call(this, this.el, on_el) :
11623 var autoToken = /\s?auto?\s?/i;
11624 var autoPlace = autoToken.test(placement);
11626 placement = placement.replace(autoToken, '') || 'top';
11630 //this.el.setXY([0,0]);
11632 this.el.dom.style.display='block';
11633 this.el.addClass(placement);
11635 //this.el.appendTo(on_el);
11637 var p = this.getPosition();
11638 var box = this.el.getBox();
11643 var align = Roo.bootstrap.Popover.alignment[placement]
11644 this.el.alignTo(on_el, align[0],align[1]);
11645 //var arrow = this.el.select('.arrow',true).first();
11646 //arrow.set(align[2],
11648 this.el.addClass('in');
11649 this.hoverState = null;
11651 if (this.el.hasClass('fade')) {
11658 this.el.setXY([0,0]);
11659 this.el.removeClass('in');
11666 Roo.bootstrap.Popover.alignment = {
11667 'left' : ['r-l', [-10,0], 'right'],
11668 'right' : ['l-r', [10,0], 'left'],
11669 'bottom' : ['t-b', [0,10], 'top'],
11670 'top' : [ 'b-t', [0,-10], 'bottom']
11681 * @class Roo.bootstrap.Progress
11682 * @extends Roo.bootstrap.Component
11683 * Bootstrap Progress class
11684 * @cfg {Boolean} striped striped of the progress bar
11685 * @cfg {Boolean} active animated of the progress bar
11689 * Create a new Progress
11690 * @param {Object} config The config object
11693 Roo.bootstrap.Progress = function(config){
11694 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
11697 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
11702 getAutoCreate : function(){
11710 cfg.cls += ' progress-striped';
11714 cfg.cls += ' active';
11733 * @class Roo.bootstrap.ProgressBar
11734 * @extends Roo.bootstrap.Component
11735 * Bootstrap ProgressBar class
11736 * @cfg {Number} aria_valuenow aria-value now
11737 * @cfg {Number} aria_valuemin aria-value min
11738 * @cfg {Number} aria_valuemax aria-value max
11739 * @cfg {String} label label for the progress bar
11740 * @cfg {String} panel (success | info | warning | danger )
11741 * @cfg {String} role role of the progress bar
11742 * @cfg {String} sr_only text
11746 * Create a new ProgressBar
11747 * @param {Object} config The config object
11750 Roo.bootstrap.ProgressBar = function(config){
11751 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
11754 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
11758 aria_valuemax : 100,
11764 getAutoCreate : function()
11769 cls: 'progress-bar',
11770 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
11782 cfg.role = this.role;
11785 if(this.aria_valuenow){
11786 cfg['aria-valuenow'] = this.aria_valuenow;
11789 if(this.aria_valuemin){
11790 cfg['aria-valuemin'] = this.aria_valuemin;
11793 if(this.aria_valuemax){
11794 cfg['aria-valuemax'] = this.aria_valuemax;
11797 if(this.label && !this.sr_only){
11798 cfg.html = this.label;
11802 cfg.cls += ' progress-bar-' + this.panel;
11808 update : function(aria_valuenow)
11810 this.aria_valuenow = aria_valuenow;
11812 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
11827 * @class Roo.bootstrap.TabPanel
11828 * @extends Roo.bootstrap.Component
11829 * Bootstrap TabPanel class
11830 * @cfg {Boolean} active panel active
11831 * @cfg {String} html panel content
11832 * @cfg {String} tabId tab relate id
11833 * @cfg {String} navId The navbar which triggers show hide
11837 * Create a new TabPanel
11838 * @param {Object} config The config object
11841 Roo.bootstrap.TabPanel = function(config){
11842 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
11846 * Fires when the active status changes
11847 * @param {Roo.bootstrap.TabPanel} this
11848 * @param {Boolean} state the new state
11855 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
11862 getAutoCreate : function(){
11866 html: this.html || ''
11870 cfg.cls += ' active';
11874 cfg.tabId = this.tabId;
11879 onRender : function(ct, position)
11881 // Roo.log("Call onRender: " + this.xtype);
11883 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
11885 if (this.navId && this.tabId) {
11886 var item = Roo.bootstrap.NavGroup.get(this.navId).getNavItem(this.tabId);
11888 Roo.log("could not find navID:" + this.navId + ", tabId: " + this.tabId);
11890 item.on('changed', function(item, state) {
11891 this.setActive(state);
11897 setActive: function(state)
11899 Roo.log("panel - set active " + this.tabId + "=" + state);
11901 this.active = state;
11903 this.el.removeClass('active');
11905 } else if (!this.el.hasClass('active')) {
11906 this.el.addClass('active');
11908 this.fireEvent('changed', this, state);
11925 * @class Roo.bootstrap.DateField
11926 * @extends Roo.bootstrap.Input
11927 * Bootstrap DateField class
11928 * @cfg {Number} weekStart default 0
11929 * @cfg {Number} weekStart default 0
11930 * @cfg {Number} viewMode default empty, (months|years)
11931 * @cfg {Number} minViewMode default empty, (months|years)
11932 * @cfg {Number} startDate default -Infinity
11933 * @cfg {Number} endDate default Infinity
11934 * @cfg {Boolean} todayHighlight default false
11935 * @cfg {Boolean} todayBtn default false
11936 * @cfg {Boolean} calendarWeeks default false
11937 * @cfg {Object} daysOfWeekDisabled default empty
11939 * @cfg {Boolean} keyboardNavigation default true
11940 * @cfg {String} language default en
11943 * Create a new DateField
11944 * @param {Object} config The config object
11947 Roo.bootstrap.DateField = function(config){
11948 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
11952 * Fires when this field show.
11953 * @param {Roo.bootstrap.DateField} this
11954 * @param {Mixed} date The date value
11959 * Fires when this field hide.
11960 * @param {Roo.bootstrap.DateField} this
11961 * @param {Mixed} date The date value
11966 * Fires when select a date.
11967 * @param {Roo.bootstrap.DateField} this
11968 * @param {Mixed} date The date value
11974 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
11977 * @cfg {String} format
11978 * The default date format string which can be overriden for localization support. The format must be
11979 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
11983 * @cfg {String} altFormats
11984 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
11985 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
11987 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
11995 todayHighlight : false,
12001 keyboardNavigation: true,
12003 calendarWeeks: false,
12005 startDate: -Infinity,
12009 daysOfWeekDisabled: [],
12013 UTCDate: function()
12015 return new Date(Date.UTC.apply(Date, arguments));
12018 UTCToday: function()
12020 var today = new Date();
12021 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
12024 getDate: function() {
12025 var d = this.getUTCDate();
12026 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
12029 getUTCDate: function() {
12033 setDate: function(d) {
12034 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
12037 setUTCDate: function(d) {
12039 this.setValue(this.formatDate(this.date));
12042 onRender: function(ct, position)
12045 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
12047 this.language = this.language || 'en';
12048 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
12049 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
12051 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
12052 this.format = this.format || 'm/d/y';
12053 this.isInline = false;
12054 this.isInput = true;
12055 this.component = this.el.select('.add-on', true).first() || false;
12056 this.component = (this.component && this.component.length === 0) ? false : this.component;
12057 this.hasInput = this.component && this.inputEL().length;
12059 if (typeof(this.minViewMode === 'string')) {
12060 switch (this.minViewMode) {
12062 this.minViewMode = 1;
12065 this.minViewMode = 2;
12068 this.minViewMode = 0;
12073 if (typeof(this.viewMode === 'string')) {
12074 switch (this.viewMode) {
12087 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
12089 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12091 this.picker().on('mousedown', this.onMousedown, this);
12092 this.picker().on('click', this.onClick, this);
12094 this.picker().addClass('datepicker-dropdown');
12096 this.startViewMode = this.viewMode;
12099 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
12100 if(!this.calendarWeeks){
12105 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
12106 v.attr('colspan', function(i, val){
12107 return parseInt(val) + 1;
12112 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
12114 this.setStartDate(this.startDate);
12115 this.setEndDate(this.endDate);
12117 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
12124 if(this.isInline) {
12129 picker : function()
12131 return this.el.select('.datepicker', true).first();
12134 fillDow: function()
12136 var dowCnt = this.weekStart;
12145 if(this.calendarWeeks){
12153 while (dowCnt < this.weekStart + 7) {
12157 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
12161 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
12164 fillMonths: function()
12167 var months = this.picker().select('>.datepicker-months td', true).first();
12169 months.dom.innerHTML = '';
12175 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
12178 months.createChild(month);
12183 update: function(){
12185 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
12187 if (this.date < this.startDate) {
12188 this.viewDate = new Date(this.startDate);
12189 } else if (this.date > this.endDate) {
12190 this.viewDate = new Date(this.endDate);
12192 this.viewDate = new Date(this.date);
12199 var d = new Date(this.viewDate),
12200 year = d.getUTCFullYear(),
12201 month = d.getUTCMonth(),
12202 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
12203 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
12204 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
12205 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
12206 currentDate = this.date && this.date.valueOf(),
12207 today = this.UTCToday();
12209 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
12211 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
12213 // this.picker.select('>tfoot th.today').
12214 // .text(dates[this.language].today)
12215 // .toggle(this.todayBtn !== false);
12217 this.updateNavArrows();
12220 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
12222 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
12224 prevMonth.setUTCDate(day);
12226 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
12228 var nextMonth = new Date(prevMonth);
12230 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
12232 nextMonth = nextMonth.valueOf();
12234 var fillMonths = false;
12236 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
12238 while(prevMonth.valueOf() < nextMonth) {
12241 if (prevMonth.getUTCDay() === this.weekStart) {
12243 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
12251 if(this.calendarWeeks){
12252 // ISO 8601: First week contains first thursday.
12253 // ISO also states week starts on Monday, but we can be more abstract here.
12255 // Start of current week: based on weekstart/current date
12256 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
12257 // Thursday of this week
12258 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
12259 // First Thursday of year, year from thursday
12260 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
12261 // Calendar week: ms between thursdays, div ms per day, div 7 days
12262 calWeek = (th - yth) / 864e5 / 7 + 1;
12264 fillMonths.cn.push({
12272 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
12274 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
12277 if (this.todayHighlight &&
12278 prevMonth.getUTCFullYear() == today.getFullYear() &&
12279 prevMonth.getUTCMonth() == today.getMonth() &&
12280 prevMonth.getUTCDate() == today.getDate()) {
12281 clsName += ' today';
12284 if (currentDate && prevMonth.valueOf() === currentDate) {
12285 clsName += ' active';
12288 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
12289 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
12290 clsName += ' disabled';
12293 fillMonths.cn.push({
12295 cls: 'day ' + clsName,
12296 html: prevMonth.getDate()
12299 prevMonth.setDate(prevMonth.getDate()+1);
12302 var currentYear = this.date && this.date.getUTCFullYear();
12303 var currentMonth = this.date && this.date.getUTCMonth();
12305 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
12307 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
12308 v.removeClass('active');
12310 if(currentYear === year && k === currentMonth){
12311 v.addClass('active');
12314 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
12315 v.addClass('disabled');
12321 year = parseInt(year/10, 10) * 10;
12323 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
12325 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
12328 for (var i = -1; i < 11; i++) {
12329 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
12331 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
12339 showMode: function(dir) {
12341 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
12343 Roo.each(this.picker().select('>div',true).elements, function(v){
12344 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12347 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
12352 if(this.isInline) return;
12354 this.picker().removeClass(['bottom', 'top']);
12356 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
12358 * place to the top of element!
12362 this.picker().addClass('top');
12363 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12368 this.picker().addClass('bottom');
12370 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12373 parseDate : function(value){
12374 if(!value || value instanceof Date){
12377 var v = Date.parseDate(value, this.format);
12378 if (!v && this.useIso) {
12379 v = Date.parseDate(value, 'Y-m-d');
12381 if(!v && this.altFormats){
12382 if(!this.altFormatsArray){
12383 this.altFormatsArray = this.altFormats.split("|");
12385 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
12386 v = Date.parseDate(value, this.altFormatsArray[i]);
12392 formatDate : function(date, fmt){
12393 return (!date || !(date instanceof Date)) ?
12394 date : date.dateFormat(fmt || this.format);
12397 onFocus : function()
12399 Roo.bootstrap.DateField.superclass.onFocus.call(this);
12403 onBlur : function()
12405 Roo.bootstrap.DateField.superclass.onBlur.call(this);
12411 this.picker().show();
12415 this.fireEvent('show', this, this.date);
12420 if(this.isInline) return;
12421 this.picker().hide();
12422 this.viewMode = this.startViewMode;
12425 this.fireEvent('hide', this, this.date);
12429 onMousedown: function(e){
12430 e.stopPropagation();
12431 e.preventDefault();
12434 keyup: function(e){
12435 Roo.bootstrap.DateField.superclass.keyup.call(this);
12440 setValue: function(v){
12441 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
12443 this.fireEvent('select', this, this.date);
12447 fireKey: function(e){
12448 if (!this.picker().isVisible()){
12449 if (e.keyCode == 27) // allow escape to hide and re-show picker
12453 var dateChanged = false,
12455 newDate, newViewDate;
12459 e.preventDefault();
12463 if (!this.keyboardNavigation) break;
12464 dir = e.keyCode == 37 ? -1 : 1;
12467 newDate = this.moveYear(this.date, dir);
12468 newViewDate = this.moveYear(this.viewDate, dir);
12469 } else if (e.shiftKey){
12470 newDate = this.moveMonth(this.date, dir);
12471 newViewDate = this.moveMonth(this.viewDate, dir);
12473 newDate = new Date(this.date);
12474 newDate.setUTCDate(this.date.getUTCDate() + dir);
12475 newViewDate = new Date(this.viewDate);
12476 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
12478 if (this.dateWithinRange(newDate)){
12479 this.date = newDate;
12480 this.viewDate = newViewDate;
12481 this.setValue(this.formatDate(this.date));
12483 e.preventDefault();
12484 dateChanged = true;
12489 if (!this.keyboardNavigation) break;
12490 dir = e.keyCode == 38 ? -1 : 1;
12492 newDate = this.moveYear(this.date, dir);
12493 newViewDate = this.moveYear(this.viewDate, dir);
12494 } else if (e.shiftKey){
12495 newDate = this.moveMonth(this.date, dir);
12496 newViewDate = this.moveMonth(this.viewDate, dir);
12498 newDate = new Date(this.date);
12499 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
12500 newViewDate = new Date(this.viewDate);
12501 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
12503 if (this.dateWithinRange(newDate)){
12504 this.date = newDate;
12505 this.viewDate = newViewDate;
12506 this.setValue(this.formatDate(this.date));
12508 e.preventDefault();
12509 dateChanged = true;
12513 this.setValue(this.formatDate(this.date));
12515 e.preventDefault();
12518 this.setValue(this.formatDate(this.date));
12525 onClick: function(e) {
12526 e.stopPropagation();
12527 e.preventDefault();
12529 var target = e.getTarget();
12531 if(target.nodeName.toLowerCase() === 'i'){
12532 target = Roo.get(target).dom.parentNode;
12535 var nodeName = target.nodeName;
12536 var className = target.className;
12537 var html = target.innerHTML;
12539 switch(nodeName.toLowerCase()) {
12541 switch(className) {
12547 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
12548 switch(this.viewMode){
12550 this.viewDate = this.moveMonth(this.viewDate, dir);
12554 this.viewDate = this.moveYear(this.viewDate, dir);
12560 var date = new Date();
12561 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
12563 this.setValue(this.formatDate(this.date));
12569 if (className.indexOf('disabled') === -1) {
12570 this.viewDate.setUTCDate(1);
12571 if (className.indexOf('month') !== -1) {
12572 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
12574 var year = parseInt(html, 10) || 0;
12575 this.viewDate.setUTCFullYear(year);
12584 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
12585 var day = parseInt(html, 10) || 1;
12586 var year = this.viewDate.getUTCFullYear(),
12587 month = this.viewDate.getUTCMonth();
12589 if (className.indexOf('old') !== -1) {
12596 } else if (className.indexOf('new') !== -1) {
12604 this.date = this.UTCDate(year, month, day,0,0,0,0);
12605 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
12607 this.setValue(this.formatDate(this.date));
12614 setStartDate: function(startDate){
12615 this.startDate = startDate || -Infinity;
12616 if (this.startDate !== -Infinity) {
12617 this.startDate = this.parseDate(this.startDate);
12620 this.updateNavArrows();
12623 setEndDate: function(endDate){
12624 this.endDate = endDate || Infinity;
12625 if (this.endDate !== Infinity) {
12626 this.endDate = this.parseDate(this.endDate);
12629 this.updateNavArrows();
12632 setDaysOfWeekDisabled: function(daysOfWeekDisabled){
12633 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
12634 if (typeof(this.daysOfWeekDisabled) !== 'object') {
12635 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
12637 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
12638 return parseInt(d, 10);
12641 this.updateNavArrows();
12644 updateNavArrows: function() {
12645 var d = new Date(this.viewDate),
12646 year = d.getUTCFullYear(),
12647 month = d.getUTCMonth();
12649 Roo.each(this.picker().select('.prev', true).elements, function(v){
12651 switch (this.viewMode) {
12654 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
12660 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
12667 Roo.each(this.picker().select('.next', true).elements, function(v){
12669 switch (this.viewMode) {
12672 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
12678 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
12686 moveMonth: function(date, dir){
12687 if (!dir) return date;
12688 var new_date = new Date(date.valueOf()),
12689 day = new_date.getUTCDate(),
12690 month = new_date.getUTCMonth(),
12691 mag = Math.abs(dir),
12693 dir = dir > 0 ? 1 : -1;
12696 // If going back one month, make sure month is not current month
12697 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
12699 return new_date.getUTCMonth() == month;
12701 // If going forward one month, make sure month is as expected
12702 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
12704 return new_date.getUTCMonth() != new_month;
12706 new_month = month + dir;
12707 new_date.setUTCMonth(new_month);
12708 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
12709 if (new_month < 0 || new_month > 11)
12710 new_month = (new_month + 12) % 12;
12712 // For magnitudes >1, move one month at a time...
12713 for (var i=0; i<mag; i++)
12714 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
12715 new_date = this.moveMonth(new_date, dir);
12716 // ...then reset the day, keeping it in the new month
12717 new_month = new_date.getUTCMonth();
12718 new_date.setUTCDate(day);
12720 return new_month != new_date.getUTCMonth();
12723 // Common date-resetting loop -- if date is beyond end of month, make it
12726 new_date.setUTCDate(--day);
12727 new_date.setUTCMonth(new_month);
12732 moveYear: function(date, dir){
12733 return this.moveMonth(date, dir*12);
12736 dateWithinRange: function(date){
12737 return date >= this.startDate && date <= this.endDate;
12741 remove: function() {
12742 this.picker().remove();
12747 Roo.apply(Roo.bootstrap.DateField, {
12758 html: '<i class="icon-arrow-left"/>'
12768 html: '<i class="icon-arrow-right"/>'
12810 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
12811 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
12812 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
12813 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
12814 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
12827 navFnc: 'FullYear',
12832 navFnc: 'FullYear',
12837 Roo.apply(Roo.bootstrap.DateField, {
12841 cls: 'datepicker dropdown-menu',
12845 cls: 'datepicker-days',
12849 cls: 'table-condensed',
12851 Roo.bootstrap.DateField.head,
12855 Roo.bootstrap.DateField.footer
12862 cls: 'datepicker-months',
12866 cls: 'table-condensed',
12868 Roo.bootstrap.DateField.head,
12869 Roo.bootstrap.DateField.content,
12870 Roo.bootstrap.DateField.footer
12877 cls: 'datepicker-years',
12881 cls: 'table-condensed',
12883 Roo.bootstrap.DateField.head,
12884 Roo.bootstrap.DateField.content,
12885 Roo.bootstrap.DateField.footer
12904 * @class Roo.bootstrap.TimeField
12905 * @extends Roo.bootstrap.Input
12906 * Bootstrap DateField class
12910 * Create a new TimeField
12911 * @param {Object} config The config object
12914 Roo.bootstrap.TimeField = function(config){
12915 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
12919 * Fires when this field show.
12920 * @param {Roo.bootstrap.DateField} this
12921 * @param {Mixed} date The date value
12926 * Fires when this field hide.
12927 * @param {Roo.bootstrap.DateField} this
12928 * @param {Mixed} date The date value
12933 * Fires when select a date.
12934 * @param {Roo.bootstrap.DateField} this
12935 * @param {Mixed} date The date value
12941 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
12944 * @cfg {String} format
12945 * The default time format string which can be overriden for localization support. The format must be
12946 * valid according to {@link Date#parseDate} (defaults to 'H:i').
12950 onRender: function(ct, position)
12953 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
12955 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
12957 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12959 this.pop = this.picker().select('>.datepicker-time',true).first();
12960 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
12962 this.picker().on('mousedown', this.onMousedown, this);
12963 this.picker().on('click', this.onClick, this);
12965 this.picker().addClass('datepicker-dropdown');
12970 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
12971 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
12972 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
12973 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
12974 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
12975 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
12979 fireKey: function(e){
12980 if (!this.picker().isVisible()){
12981 if (e.keyCode == 27) // allow escape to hide and re-show picker
12986 e.preventDefault();
12994 this.onTogglePeriod();
12997 this.onIncrementMinutes();
13000 this.onDecrementMinutes();
13009 onClick: function(e) {
13010 e.stopPropagation();
13011 e.preventDefault();
13014 picker : function()
13016 return this.el.select('.datepicker', true).first();
13019 fillTime: function()
13021 var time = this.pop.select('tbody', true).first();
13023 time.dom.innerHTML = '';
13038 cls: 'hours-up glyphicon glyphicon-chevron-up'
13058 cls: 'minutes-up glyphicon glyphicon-chevron-up'
13079 cls: 'timepicker-hour',
13094 cls: 'timepicker-minute',
13109 cls: 'btn btn-primary period',
13131 cls: 'hours-down glyphicon glyphicon-chevron-down'
13151 cls: 'minutes-down glyphicon glyphicon-chevron-down'
13169 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
13176 var hours = this.time.getHours();
13177 var minutes = this.time.getMinutes();
13190 hours = hours - 12;
13194 hours = '0' + hours;
13198 minutes = '0' + minutes;
13201 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
13202 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
13203 this.pop.select('button', true).first().dom.innerHTML = period;
13209 this.picker().removeClass(['bottom', 'top']);
13211 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
13213 * place to the top of element!
13217 this.picker().addClass('top');
13218 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13223 this.picker().addClass('bottom');
13225 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13228 onFocus : function()
13230 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
13234 onBlur : function()
13236 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
13242 this.picker().show();
13247 this.fireEvent('show', this, this.date);
13252 this.picker().hide();
13255 this.fireEvent('hide', this, this.date);
13258 setTime : function()
13261 this.setValue(this.time.format(this.format));
13263 this.fireEvent('select', this, this.date);
13268 onMousedown: function(e){
13269 e.stopPropagation();
13270 e.preventDefault();
13273 onIncrementHours: function()
13275 Roo.log('onIncrementHours');
13276 this.time = this.time.add(Date.HOUR, 1);
13281 onDecrementHours: function()
13283 Roo.log('onDecrementHours');
13284 this.time = this.time.add(Date.HOUR, -1);
13288 onIncrementMinutes: function()
13290 Roo.log('onIncrementMinutes');
13291 this.time = this.time.add(Date.MINUTE, 1);
13295 onDecrementMinutes: function()
13297 Roo.log('onDecrementMinutes');
13298 this.time = this.time.add(Date.MINUTE, -1);
13302 onTogglePeriod: function()
13304 Roo.log('onTogglePeriod');
13305 this.time = this.time.add(Date.HOUR, 12);
13312 Roo.apply(Roo.bootstrap.TimeField, {
13342 cls: 'btn btn-info ok',
13354 Roo.apply(Roo.bootstrap.TimeField, {
13358 cls: 'datepicker dropdown-menu',
13362 cls: 'datepicker-time',
13366 cls: 'table-condensed',
13368 Roo.bootstrap.TimeField.content,
13369 Roo.bootstrap.TimeField.footer
13388 * @class Roo.bootstrap.CheckBox
13389 * @extends Roo.bootstrap.Input
13390 * Bootstrap CheckBox class
13392 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
13393 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
13394 * @cfg {String} boxLabel The text that appears beside the checkbox
13395 * @cfg {Boolean} checked initnal the element
13398 * Create a new CheckBox
13399 * @param {Object} config The config object
13402 Roo.bootstrap.CheckBox = function(config){
13403 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
13408 * Fires when the element is checked or unchecked.
13409 * @param {Roo.bootstrap.CheckBox} this This input
13410 * @param {Boolean} checked The new checked value
13416 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
13418 inputType: 'checkbox',
13424 getAutoCreate : function()
13426 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
13432 cfg.cls = 'form-group' //input-group
13437 type : this.inputType,
13438 value : (!this.checked) ? this.valueOff : this.inputValue,
13440 placeholder : this.placeholder || ''
13444 if (this.disabled) {
13445 input.disabled=true;
13449 input.checked = this.checked;
13453 input.name = this.name;
13457 input.cls += ' input-' + this.size;
13461 ['xs','sm','md','lg'].map(function(size){
13462 if (settings[size]) {
13463 cfg.cls += ' col-' + size + '-' + settings[size];
13467 var inputblock = input;
13469 if (this.before || this.after) {
13472 cls : 'input-group',
13476 inputblock.cn.push({
13478 cls : 'input-group-addon',
13482 inputblock.cn.push(input);
13484 inputblock.cn.push({
13486 cls : 'input-group-addon',
13493 if (align ==='left' && this.fieldLabel.length) {
13494 Roo.log("left and has label");
13500 cls : 'control-label col-md-' + this.labelWidth,
13501 html : this.fieldLabel
13505 cls : "col-md-" + (12 - this.labelWidth),
13512 } else if ( this.fieldLabel.length) {
13517 tag: this.boxLabel ? 'span' : 'label',
13519 cls: 'control-label box-input-label',
13520 //cls : 'input-group-addon',
13521 html : this.fieldLabel
13531 Roo.log(" no label && no align");
13546 html: this.boxLabel
13555 * return the real input element.
13557 inputEl: function ()
13559 return this.el.select('input.form-box',true).first();
13564 return this.el.select('label.control-label',true).first();
13567 initEvents : function()
13569 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
13571 this.inputEl().on('click', this.onClick, this);
13575 onClick : function()
13577 this.setChecked(!this.checked);
13580 setChecked : function(state,suppressEvent)
13582 this.checked = state;
13584 this.inputEl().dom.checked = state;
13586 if(suppressEvent !== true){
13587 this.fireEvent('check', this, state);
13590 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
13594 setValue : function(v,suppressEvent)
13596 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
13610 * @class Roo.bootstrap.Radio
13611 * @extends Roo.bootstrap.CheckBox
13612 * Bootstrap Radio class
13615 * Create a new Radio
13616 * @param {Object} config The config object
13619 Roo.bootstrap.Radio = function(config){
13620 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
13624 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
13626 inputType: 'radio',
13630 getAutoCreate : function()
13632 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
13638 cfg.cls = 'form-group' //input-group
13643 type : this.inputType,
13644 value : (!this.checked) ? this.valueOff : this.inputValue,
13646 placeholder : this.placeholder || ''
13650 if (this.disabled) {
13651 input.disabled=true;
13655 input.checked = this.checked;
13659 input.name = this.name;
13663 input.cls += ' input-' + this.size;
13667 ['xs','sm','md','lg'].map(function(size){
13668 if (settings[size]) {
13669 cfg.cls += ' col-' + size + '-' + settings[size];
13673 var inputblock = input;
13675 if (this.before || this.after) {
13678 cls : 'input-group',
13682 inputblock.cn.push({
13684 cls : 'input-group-addon',
13688 inputblock.cn.push(input);
13690 inputblock.cn.push({
13692 cls : 'input-group-addon',
13699 if (align ==='left' && this.fieldLabel.length) {
13700 Roo.log("left and has label");
13706 cls : 'control-label col-md-' + this.labelWidth,
13707 html : this.fieldLabel
13711 cls : "col-md-" + (12 - this.labelWidth),
13718 } else if ( this.fieldLabel.length) {
13725 cls: 'control-label box-input-label',
13726 //cls : 'input-group-addon',
13727 html : this.fieldLabel
13737 Roo.log(" no label && no align");
13752 html: this.boxLabel
13760 onClick : function()
13762 this.setChecked(true);
13765 setChecked : function(state,suppressEvent)
13768 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
13769 v.dom.checked = false;
13773 this.checked = state;
13774 this.inputEl().dom.checked = state;
13776 if(suppressEvent !== true){
13777 this.fireEvent('check', this, state);
13780 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
13784 getGroupValue : function()
13787 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
13788 if(v.dom.checked == true){
13789 value = v.dom.value;
13797 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
13798 * @return {Mixed} value The field value
13800 getValue : function(){
13801 return this.getGroupValue();
13807 //<script type="text/javascript">
13810 * Based Ext JS Library 1.1.1
13811 * Copyright(c) 2006-2007, Ext JS, LLC.
13817 * @class Roo.HtmlEditorCore
13818 * @extends Roo.Component
13819 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
13821 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
13824 Roo.HtmlEditorCore = function(config){
13827 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
13830 * @event initialize
13831 * Fires when the editor is fully initialized (including the iframe)
13832 * @param {Roo.HtmlEditorCore} this
13837 * Fires when the editor is first receives the focus. Any insertion must wait
13838 * until after this event.
13839 * @param {Roo.HtmlEditorCore} this
13843 * @event beforesync
13844 * Fires before the textarea is updated with content from the editor iframe. Return false
13845 * to cancel the sync.
13846 * @param {Roo.HtmlEditorCore} this
13847 * @param {String} html
13851 * @event beforepush
13852 * Fires before the iframe editor is updated with content from the textarea. Return false
13853 * to cancel the push.
13854 * @param {Roo.HtmlEditorCore} this
13855 * @param {String} html
13860 * Fires when the textarea is updated with content from the editor iframe.
13861 * @param {Roo.HtmlEditorCore} this
13862 * @param {String} html
13867 * Fires when the iframe editor is updated with content from the textarea.
13868 * @param {Roo.HtmlEditorCore} this
13869 * @param {String} html
13874 * @event editorevent
13875 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
13876 * @param {Roo.HtmlEditorCore} this
13884 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
13888 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
13894 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
13899 * @cfg {Number} height (in pixels)
13903 * @cfg {Number} width (in pixels)
13908 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
13911 stylesheets: false,
13916 // private properties
13917 validationEvent : false,
13919 initialized : false,
13921 sourceEditMode : false,
13922 onFocus : Roo.emptyFn,
13924 hideMode:'offsets',
13932 * Protected method that will not generally be called directly. It
13933 * is called when the editor initializes the iframe with HTML contents. Override this method if you
13934 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
13936 getDocMarkup : function(){
13939 Roo.log(this.stylesheets);
13941 // inherit styels from page...??
13942 if (this.stylesheets === false) {
13944 Roo.get(document.head).select('style').each(function(node) {
13945 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
13948 Roo.get(document.head).select('link').each(function(node) {
13949 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
13952 } else if (!this.stylesheets.length) {
13954 st = '<style type="text/css">' +
13955 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
13958 Roo.each(this.stylesheets, function(s) {
13959 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
13964 st += '<style type="text/css">' +
13965 'IMG { cursor: pointer } ' +
13969 return '<html><head>' + st +
13970 //<style type="text/css">' +
13971 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
13973 ' </head><body class="roo-htmleditor-body"></body></html>';
13977 onRender : function(ct, position)
13980 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
13981 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
13984 this.el.dom.style.border = '0 none';
13985 this.el.dom.setAttribute('tabIndex', -1);
13986 this.el.addClass('x-hidden hide');
13990 if(Roo.isIE){ // fix IE 1px bogus margin
13991 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
13995 this.frameId = Roo.id();
13999 var iframe = this.owner.wrap.createChild({
14001 cls: 'form-control', // bootstrap..
14003 name: this.frameId,
14004 frameBorder : 'no',
14005 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
14010 this.iframe = iframe.dom;
14012 this.assignDocWin();
14014 this.doc.designMode = 'on';
14017 this.doc.write(this.getDocMarkup());
14021 var task = { // must defer to wait for browser to be ready
14023 //console.log("run task?" + this.doc.readyState);
14024 this.assignDocWin();
14025 if(this.doc.body || this.doc.readyState == 'complete'){
14027 this.doc.designMode="on";
14031 Roo.TaskMgr.stop(task);
14032 this.initEditor.defer(10, this);
14039 Roo.TaskMgr.start(task);
14046 onResize : function(w, h)
14048 Roo.log('resize: ' +w + ',' + h );
14049 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
14053 if(typeof w == 'number'){
14055 this.iframe.style.width = w + 'px';
14057 if(typeof h == 'number'){
14059 this.iframe.style.height = h + 'px';
14061 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
14068 * Toggles the editor between standard and source edit mode.
14069 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
14071 toggleSourceEdit : function(sourceEditMode){
14073 this.sourceEditMode = sourceEditMode === true;
14075 if(this.sourceEditMode){
14077 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
14080 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
14081 //this.iframe.className = '';
14084 //this.setSize(this.owner.wrap.getSize());
14085 //this.fireEvent('editmodechange', this, this.sourceEditMode);
14092 * Protected method that will not generally be called directly. If you need/want
14093 * custom HTML cleanup, this is the method you should override.
14094 * @param {String} html The HTML to be cleaned
14095 * return {String} The cleaned HTML
14097 cleanHtml : function(html){
14098 html = String(html);
14099 if(html.length > 5){
14100 if(Roo.isSafari){ // strip safari nonsense
14101 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
14104 if(html == ' '){
14111 * HTML Editor -> Textarea
14112 * Protected method that will not generally be called directly. Syncs the contents
14113 * of the editor iframe with the textarea.
14115 syncValue : function(){
14116 if(this.initialized){
14117 var bd = (this.doc.body || this.doc.documentElement);
14118 //this.cleanUpPaste(); -- this is done else where and causes havoc..
14119 var html = bd.innerHTML;
14121 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
14122 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
14124 html = '<div style="'+m[0]+'">' + html + '</div>';
14127 html = this.cleanHtml(html);
14128 // fix up the special chars.. normaly like back quotes in word...
14129 // however we do not want to do this with chinese..
14130 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
14131 var cc = b.charCodeAt();
14133 (cc >= 0x4E00 && cc < 0xA000 ) ||
14134 (cc >= 0x3400 && cc < 0x4E00 ) ||
14135 (cc >= 0xf900 && cc < 0xfb00 )
14141 if(this.owner.fireEvent('beforesync', this, html) !== false){
14142 this.el.dom.value = html;
14143 this.owner.fireEvent('sync', this, html);
14149 * Protected method that will not generally be called directly. Pushes the value of the textarea
14150 * into the iframe editor.
14152 pushValue : function(){
14153 if(this.initialized){
14154 var v = this.el.dom.value.trim();
14156 // if(v.length < 1){
14160 if(this.owner.fireEvent('beforepush', this, v) !== false){
14161 var d = (this.doc.body || this.doc.documentElement);
14163 this.cleanUpPaste();
14164 this.el.dom.value = d.innerHTML;
14165 this.owner.fireEvent('push', this, v);
14171 deferFocus : function(){
14172 this.focus.defer(10, this);
14176 focus : function(){
14177 if(this.win && !this.sourceEditMode){
14184 assignDocWin: function()
14186 var iframe = this.iframe;
14189 this.doc = iframe.contentWindow.document;
14190 this.win = iframe.contentWindow;
14192 if (!Roo.get(this.frameId)) {
14195 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
14196 this.win = Roo.get(this.frameId).dom.contentWindow;
14201 initEditor : function(){
14202 //console.log("INIT EDITOR");
14203 this.assignDocWin();
14207 this.doc.designMode="on";
14209 this.doc.write(this.getDocMarkup());
14212 var dbody = (this.doc.body || this.doc.documentElement);
14213 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
14214 // this copies styles from the containing element into thsi one..
14215 // not sure why we need all of this..
14216 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
14217 ss['background-attachment'] = 'fixed'; // w3c
14218 dbody.bgProperties = 'fixed'; // ie
14219 Roo.DomHelper.applyStyles(dbody, ss);
14220 Roo.EventManager.on(this.doc, {
14221 //'mousedown': this.onEditorEvent,
14222 'mouseup': this.onEditorEvent,
14223 'dblclick': this.onEditorEvent,
14224 'click': this.onEditorEvent,
14225 'keyup': this.onEditorEvent,
14230 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
14232 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
14233 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
14235 this.initialized = true;
14237 this.owner.fireEvent('initialize', this);
14242 onDestroy : function(){
14248 //for (var i =0; i < this.toolbars.length;i++) {
14249 // // fixme - ask toolbars for heights?
14250 // this.toolbars[i].onDestroy();
14253 //this.wrap.dom.innerHTML = '';
14254 //this.wrap.remove();
14259 onFirstFocus : function(){
14261 this.assignDocWin();
14264 this.activated = true;
14267 if(Roo.isGecko){ // prevent silly gecko errors
14269 var s = this.win.getSelection();
14270 if(!s.focusNode || s.focusNode.nodeType != 3){
14271 var r = s.getRangeAt(0);
14272 r.selectNodeContents((this.doc.body || this.doc.documentElement));
14277 this.execCmd('useCSS', true);
14278 this.execCmd('styleWithCSS', false);
14281 this.owner.fireEvent('activate', this);
14285 adjustFont: function(btn){
14286 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
14287 //if(Roo.isSafari){ // safari
14290 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
14291 if(Roo.isSafari){ // safari
14292 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
14293 v = (v < 10) ? 10 : v;
14294 v = (v > 48) ? 48 : v;
14295 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
14300 v = Math.max(1, v+adjust);
14302 this.execCmd('FontSize', v );
14305 onEditorEvent : function(e){
14306 this.owner.fireEvent('editorevent', this, e);
14307 // this.updateToolbar();
14308 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
14311 insertTag : function(tg)
14313 // could be a bit smarter... -> wrap the current selected tRoo..
14314 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
14316 range = this.createRange(this.getSelection());
14317 var wrappingNode = this.doc.createElement(tg.toLowerCase());
14318 wrappingNode.appendChild(range.extractContents());
14319 range.insertNode(wrappingNode);
14326 this.execCmd("formatblock", tg);
14330 insertText : function(txt)
14334 var range = this.createRange();
14335 range.deleteContents();
14336 //alert(Sender.getAttribute('label'));
14338 range.insertNode(this.doc.createTextNode(txt));
14344 * Executes a Midas editor command on the editor document and performs necessary focus and
14345 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
14346 * @param {String} cmd The Midas command
14347 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
14349 relayCmd : function(cmd, value){
14351 this.execCmd(cmd, value);
14352 this.owner.fireEvent('editorevent', this);
14353 //this.updateToolbar();
14354 this.owner.deferFocus();
14358 * Executes a Midas editor command directly on the editor document.
14359 * For visual commands, you should use {@link #relayCmd} instead.
14360 * <b>This should only be called after the editor is initialized.</b>
14361 * @param {String} cmd The Midas command
14362 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
14364 execCmd : function(cmd, value){
14365 this.doc.execCommand(cmd, false, value === undefined ? null : value);
14372 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
14374 * @param {String} text | dom node..
14376 insertAtCursor : function(text)
14381 if(!this.activated){
14387 var r = this.doc.selection.createRange();
14398 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
14402 // from jquery ui (MIT licenced)
14404 var win = this.win;
14406 if (win.getSelection && win.getSelection().getRangeAt) {
14407 range = win.getSelection().getRangeAt(0);
14408 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
14409 range.insertNode(node);
14410 } else if (win.document.selection && win.document.selection.createRange) {
14411 // no firefox support
14412 var txt = typeof(text) == 'string' ? text : text.outerHTML;
14413 win.document.selection.createRange().pasteHTML(txt);
14415 // no firefox support
14416 var txt = typeof(text) == 'string' ? text : text.outerHTML;
14417 this.execCmd('InsertHTML', txt);
14426 mozKeyPress : function(e){
14428 var c = e.getCharCode(), cmd;
14431 c = String.fromCharCode(c).toLowerCase();
14445 this.cleanUpPaste.defer(100, this);
14453 e.preventDefault();
14461 fixKeys : function(){ // load time branching for fastest keydown performance
14463 return function(e){
14464 var k = e.getKey(), r;
14467 r = this.doc.selection.createRange();
14470 r.pasteHTML('    ');
14477 r = this.doc.selection.createRange();
14479 var target = r.parentElement();
14480 if(!target || target.tagName.toLowerCase() != 'li'){
14482 r.pasteHTML('<br />');
14488 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
14489 this.cleanUpPaste.defer(100, this);
14495 }else if(Roo.isOpera){
14496 return function(e){
14497 var k = e.getKey();
14501 this.execCmd('InsertHTML','    ');
14504 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
14505 this.cleanUpPaste.defer(100, this);
14510 }else if(Roo.isSafari){
14511 return function(e){
14512 var k = e.getKey();
14516 this.execCmd('InsertText','\t');
14520 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
14521 this.cleanUpPaste.defer(100, this);
14529 getAllAncestors: function()
14531 var p = this.getSelectedNode();
14534 a.push(p); // push blank onto stack..
14535 p = this.getParentElement();
14539 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
14543 a.push(this.doc.body);
14547 lastSelNode : false,
14550 getSelection : function()
14552 this.assignDocWin();
14553 return Roo.isIE ? this.doc.selection : this.win.getSelection();
14556 getSelectedNode: function()
14558 // this may only work on Gecko!!!
14560 // should we cache this!!!!
14565 var range = this.createRange(this.getSelection()).cloneRange();
14568 var parent = range.parentElement();
14570 var testRange = range.duplicate();
14571 testRange.moveToElementText(parent);
14572 if (testRange.inRange(range)) {
14575 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
14578 parent = parent.parentElement;
14583 // is ancestor a text element.
14584 var ac = range.commonAncestorContainer;
14585 if (ac.nodeType == 3) {
14586 ac = ac.parentNode;
14589 var ar = ac.childNodes;
14592 var other_nodes = [];
14593 var has_other_nodes = false;
14594 for (var i=0;i<ar.length;i++) {
14595 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
14598 // fullly contained node.
14600 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
14605 // probably selected..
14606 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
14607 other_nodes.push(ar[i]);
14611 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
14616 has_other_nodes = true;
14618 if (!nodes.length && other_nodes.length) {
14619 nodes= other_nodes;
14621 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
14627 createRange: function(sel)
14629 // this has strange effects when using with
14630 // top toolbar - not sure if it's a great idea.
14631 //this.editor.contentWindow.focus();
14632 if (typeof sel != "undefined") {
14634 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
14636 return this.doc.createRange();
14639 return this.doc.createRange();
14642 getParentElement: function()
14645 this.assignDocWin();
14646 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
14648 var range = this.createRange(sel);
14651 var p = range.commonAncestorContainer;
14652 while (p.nodeType == 3) { // text node
14663 * Range intersection.. the hard stuff...
14667 * [ -- selected range --- ]
14671 * if end is before start or hits it. fail.
14672 * if start is after end or hits it fail.
14674 * if either hits (but other is outside. - then it's not
14680 // @see http://www.thismuchiknow.co.uk/?p=64.
14681 rangeIntersectsNode : function(range, node)
14683 var nodeRange = node.ownerDocument.createRange();
14685 nodeRange.selectNode(node);
14687 nodeRange.selectNodeContents(node);
14690 var rangeStartRange = range.cloneRange();
14691 rangeStartRange.collapse(true);
14693 var rangeEndRange = range.cloneRange();
14694 rangeEndRange.collapse(false);
14696 var nodeStartRange = nodeRange.cloneRange();
14697 nodeStartRange.collapse(true);
14699 var nodeEndRange = nodeRange.cloneRange();
14700 nodeEndRange.collapse(false);
14702 return rangeStartRange.compareBoundaryPoints(
14703 Range.START_TO_START, nodeEndRange) == -1 &&
14704 rangeEndRange.compareBoundaryPoints(
14705 Range.START_TO_START, nodeStartRange) == 1;
14709 rangeCompareNode : function(range, node)
14711 var nodeRange = node.ownerDocument.createRange();
14713 nodeRange.selectNode(node);
14715 nodeRange.selectNodeContents(node);
14719 range.collapse(true);
14721 nodeRange.collapse(true);
14723 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
14724 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
14726 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
14728 var nodeIsBefore = ss == 1;
14729 var nodeIsAfter = ee == -1;
14731 if (nodeIsBefore && nodeIsAfter)
14733 if (!nodeIsBefore && nodeIsAfter)
14734 return 1; //right trailed.
14736 if (nodeIsBefore && !nodeIsAfter)
14737 return 2; // left trailed.
14742 // private? - in a new class?
14743 cleanUpPaste : function()
14745 // cleans up the whole document..
14746 Roo.log('cleanuppaste');
14748 this.cleanUpChildren(this.doc.body);
14749 var clean = this.cleanWordChars(this.doc.body.innerHTML);
14750 if (clean != this.doc.body.innerHTML) {
14751 this.doc.body.innerHTML = clean;
14756 cleanWordChars : function(input) {// change the chars to hex code
14757 var he = Roo.HtmlEditorCore;
14759 var output = input;
14760 Roo.each(he.swapCodes, function(sw) {
14761 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
14763 output = output.replace(swapper, sw[1]);
14770 cleanUpChildren : function (n)
14772 if (!n.childNodes.length) {
14775 for (var i = n.childNodes.length-1; i > -1 ; i--) {
14776 this.cleanUpChild(n.childNodes[i]);
14783 cleanUpChild : function (node)
14786 //console.log(node);
14787 if (node.nodeName == "#text") {
14788 // clean up silly Windows -- stuff?
14791 if (node.nodeName == "#comment") {
14792 node.parentNode.removeChild(node);
14793 // clean up silly Windows -- stuff?
14797 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
14799 node.parentNode.removeChild(node);
14804 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
14806 // remove <a name=....> as rendering on yahoo mailer is borked with this.
14807 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
14809 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
14810 // remove_keep_children = true;
14813 if (remove_keep_children) {
14814 this.cleanUpChildren(node);
14815 // inserts everything just before this node...
14816 while (node.childNodes.length) {
14817 var cn = node.childNodes[0];
14818 node.removeChild(cn);
14819 node.parentNode.insertBefore(cn, node);
14821 node.parentNode.removeChild(node);
14825 if (!node.attributes || !node.attributes.length) {
14826 this.cleanUpChildren(node);
14830 function cleanAttr(n,v)
14833 if (v.match(/^\./) || v.match(/^\//)) {
14836 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
14839 if (v.match(/^#/)) {
14842 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
14843 node.removeAttribute(n);
14847 function cleanStyle(n,v)
14849 if (v.match(/expression/)) { //XSS?? should we even bother..
14850 node.removeAttribute(n);
14853 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
14854 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
14857 var parts = v.split(/;/);
14860 Roo.each(parts, function(p) {
14861 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
14865 var l = p.split(':').shift().replace(/\s+/g,'');
14866 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
14868 if ( cblack.indexOf(l) > -1) {
14869 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
14870 //node.removeAttribute(n);
14874 // only allow 'c whitelisted system attributes'
14875 if ( cwhite.length && cwhite.indexOf(l) < 0) {
14876 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
14877 //node.removeAttribute(n);
14887 if (clean.length) {
14888 node.setAttribute(n, clean.join(';'));
14890 node.removeAttribute(n);
14896 for (var i = node.attributes.length-1; i > -1 ; i--) {
14897 var a = node.attributes[i];
14900 if (a.name.toLowerCase().substr(0,2)=='on') {
14901 node.removeAttribute(a.name);
14904 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
14905 node.removeAttribute(a.name);
14908 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
14909 cleanAttr(a.name,a.value); // fixme..
14912 if (a.name == 'style') {
14913 cleanStyle(a.name,a.value);
14916 /// clean up MS crap..
14917 // tecnically this should be a list of valid class'es..
14920 if (a.name == 'class') {
14921 if (a.value.match(/^Mso/)) {
14922 node.className = '';
14925 if (a.value.match(/body/)) {
14926 node.className = '';
14937 this.cleanUpChildren(node);
14943 // hide stuff that is not compatible
14957 * @event specialkey
14961 * @cfg {String} fieldClass @hide
14964 * @cfg {String} focusClass @hide
14967 * @cfg {String} autoCreate @hide
14970 * @cfg {String} inputType @hide
14973 * @cfg {String} invalidClass @hide
14976 * @cfg {String} invalidText @hide
14979 * @cfg {String} msgFx @hide
14982 * @cfg {String} validateOnBlur @hide
14986 Roo.HtmlEditorCore.white = [
14987 'area', 'br', 'img', 'input', 'hr', 'wbr',
14989 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
14990 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
14991 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
14992 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
14993 'table', 'ul', 'xmp',
14995 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
14998 'dir', 'menu', 'ol', 'ul', 'dl',
15004 Roo.HtmlEditorCore.black = [
15005 // 'embed', 'object', // enable - backend responsiblity to clean thiese
15007 'base', 'basefont', 'bgsound', 'blink', 'body',
15008 'frame', 'frameset', 'head', 'html', 'ilayer',
15009 'iframe', 'layer', 'link', 'meta', 'object',
15010 'script', 'style' ,'title', 'xml' // clean later..
15012 Roo.HtmlEditorCore.clean = [
15013 'script', 'style', 'title', 'xml'
15015 Roo.HtmlEditorCore.remove = [
15020 Roo.HtmlEditorCore.ablack = [
15024 Roo.HtmlEditorCore.aclean = [
15025 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
15029 Roo.HtmlEditorCore.pwhite= [
15030 'http', 'https', 'mailto'
15033 // white listed style attributes.
15034 Roo.HtmlEditorCore.cwhite= [
15035 // 'text-align', /// default is to allow most things..
15041 // black listed style attributes.
15042 Roo.HtmlEditorCore.cblack= [
15043 // 'font-size' -- this can be set by the project
15047 Roo.HtmlEditorCore.swapCodes =[
15066 * @class Roo.bootstrap.HtmlEditor
15067 * @extends Roo.bootstrap.TextArea
15068 * Bootstrap HtmlEditor class
15071 * Create a new HtmlEditor
15072 * @param {Object} config The config object
15075 Roo.bootstrap.HtmlEditor = function(config){
15076 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
15077 if (!this.toolbars) {
15078 this.toolbars = [];
15080 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
15083 * @event initialize
15084 * Fires when the editor is fully initialized (including the iframe)
15085 * @param {HtmlEditor} this
15090 * Fires when the editor is first receives the focus. Any insertion must wait
15091 * until after this event.
15092 * @param {HtmlEditor} this
15096 * @event beforesync
15097 * Fires before the textarea is updated with content from the editor iframe. Return false
15098 * to cancel the sync.
15099 * @param {HtmlEditor} this
15100 * @param {String} html
15104 * @event beforepush
15105 * Fires before the iframe editor is updated with content from the textarea. Return false
15106 * to cancel the push.
15107 * @param {HtmlEditor} this
15108 * @param {String} html
15113 * Fires when the textarea is updated with content from the editor iframe.
15114 * @param {HtmlEditor} this
15115 * @param {String} html
15120 * Fires when the iframe editor is updated with content from the textarea.
15121 * @param {HtmlEditor} this
15122 * @param {String} html
15126 * @event editmodechange
15127 * Fires when the editor switches edit modes
15128 * @param {HtmlEditor} this
15129 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
15131 editmodechange: true,
15133 * @event editorevent
15134 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
15135 * @param {HtmlEditor} this
15139 * @event firstfocus
15140 * Fires when on first focus - needed by toolbars..
15141 * @param {HtmlEditor} this
15146 * Auto save the htmlEditor value as a file into Events
15147 * @param {HtmlEditor} this
15151 * @event savedpreview
15152 * preview the saved version of htmlEditor
15153 * @param {HtmlEditor} this
15160 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
15164 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
15169 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
15174 * @cfg {Number} height (in pixels)
15178 * @cfg {Number} width (in pixels)
15183 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
15186 stylesheets: false,
15191 // private properties
15192 validationEvent : false,
15194 initialized : false,
15197 onFocus : Roo.emptyFn,
15199 hideMode:'offsets',
15202 tbContainer : false,
15204 toolbarContainer :function() {
15205 return this.wrap.select('.x-html-editor-tb',true).first();
15209 * Protected method that will not generally be called directly. It
15210 * is called when the editor creates its toolbar. Override this method if you need to
15211 * add custom toolbar buttons.
15212 * @param {HtmlEditor} editor
15214 createToolbar : function(){
15216 Roo.log("create toolbars");
15218 this.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard({editor: this} ) ];
15219 this.toolbars[0].render(this.toolbarContainer());
15223 // if (!editor.toolbars || !editor.toolbars.length) {
15224 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
15227 // for (var i =0 ; i < editor.toolbars.length;i++) {
15228 // editor.toolbars[i] = Roo.factory(
15229 // typeof(editor.toolbars[i]) == 'string' ?
15230 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
15231 // Roo.bootstrap.HtmlEditor);
15232 // editor.toolbars[i].init(editor);
15238 onRender : function(ct, position)
15240 // Roo.log("Call onRender: " + this.xtype);
15242 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
15244 this.wrap = this.inputEl().wrap({
15245 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
15248 this.editorcore.onRender(ct, position);
15250 if (this.resizable) {
15251 this.resizeEl = new Roo.Resizable(this.wrap, {
15255 minHeight : this.height,
15256 height: this.height,
15257 handles : this.resizable,
15260 resize : function(r, w, h) {
15261 _t.onResize(w,h); // -something
15267 this.createToolbar(this);
15270 if(!this.width && this.resizable){
15271 this.setSize(this.wrap.getSize());
15273 if (this.resizeEl) {
15274 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
15275 // should trigger onReize..
15281 onResize : function(w, h)
15283 Roo.log('resize: ' +w + ',' + h );
15284 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
15288 if(this.inputEl() ){
15289 if(typeof w == 'number'){
15290 var aw = w - this.wrap.getFrameWidth('lr');
15291 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
15294 if(typeof h == 'number'){
15295 var tbh = -11; // fixme it needs to tool bar size!
15296 for (var i =0; i < this.toolbars.length;i++) {
15297 // fixme - ask toolbars for heights?
15298 tbh += this.toolbars[i].el.getHeight();
15299 //if (this.toolbars[i].footer) {
15300 // tbh += this.toolbars[i].footer.el.getHeight();
15308 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
15309 ah -= 5; // knock a few pixes off for look..
15310 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
15314 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
15315 this.editorcore.onResize(ew,eh);
15320 * Toggles the editor between standard and source edit mode.
15321 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
15323 toggleSourceEdit : function(sourceEditMode)
15325 this.editorcore.toggleSourceEdit(sourceEditMode);
15327 if(this.editorcore.sourceEditMode){
15328 Roo.log('editor - showing textarea');
15331 // Roo.log(this.syncValue());
15333 this.inputEl().removeClass('hide');
15334 this.inputEl().dom.removeAttribute('tabIndex');
15335 this.inputEl().focus();
15337 Roo.log('editor - hiding textarea');
15339 // Roo.log(this.pushValue());
15342 this.inputEl().addClass('hide');
15343 this.inputEl().dom.setAttribute('tabIndex', -1);
15344 //this.deferFocus();
15347 if(this.resizable){
15348 this.setSize(this.wrap.getSize());
15351 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
15354 // private (for BoxComponent)
15355 adjustSize : Roo.BoxComponent.prototype.adjustSize,
15357 // private (for BoxComponent)
15358 getResizeEl : function(){
15362 // private (for BoxComponent)
15363 getPositionEl : function(){
15368 initEvents : function(){
15369 this.originalValue = this.getValue();
15373 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
15376 // markInvalid : Roo.emptyFn,
15378 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
15381 // clearInvalid : Roo.emptyFn,
15383 setValue : function(v){
15384 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
15385 this.editorcore.pushValue();
15390 deferFocus : function(){
15391 this.focus.defer(10, this);
15395 focus : function(){
15396 this.editorcore.focus();
15402 onDestroy : function(){
15408 for (var i =0; i < this.toolbars.length;i++) {
15409 // fixme - ask toolbars for heights?
15410 this.toolbars[i].onDestroy();
15413 this.wrap.dom.innerHTML = '';
15414 this.wrap.remove();
15419 onFirstFocus : function(){
15420 //Roo.log("onFirstFocus");
15421 this.editorcore.onFirstFocus();
15422 for (var i =0; i < this.toolbars.length;i++) {
15423 this.toolbars[i].onFirstFocus();
15429 syncValue : function()
15431 this.editorcore.syncValue();
15434 pushValue : function()
15436 this.editorcore.pushValue();
15440 // hide stuff that is not compatible
15454 * @event specialkey
15458 * @cfg {String} fieldClass @hide
15461 * @cfg {String} focusClass @hide
15464 * @cfg {String} autoCreate @hide
15467 * @cfg {String} inputType @hide
15470 * @cfg {String} invalidClass @hide
15473 * @cfg {String} invalidText @hide
15476 * @cfg {String} msgFx @hide
15479 * @cfg {String} validateOnBlur @hide
15490 * @class Roo.bootstrap.HtmlEditorToolbar1
15495 new Roo.bootstrap.HtmlEditor({
15498 new Roo.bootstrap.HtmlEditorToolbar1({
15499 disable : { fonts: 1 , format: 1, ..., ... , ...],
15505 * @cfg {Object} disable List of elements to disable..
15506 * @cfg {Array} btns List of additional buttons.
15510 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
15513 Roo.bootstrap.HtmlEditor.ToolbarStandard = function(config)
15516 Roo.apply(this, config);
15518 // default disabled, based on 'good practice'..
15519 this.disable = this.disable || {};
15520 Roo.applyIf(this.disable, {
15523 specialElements : true
15525 Roo.bootstrap.HtmlEditor.ToolbarStandard.superclass.constructor.call(this, config);
15527 this.editor = config.editor;
15528 this.editorcore = config.editor.editorcore;
15530 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
15532 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
15533 // dont call parent... till later.
15535 Roo.extend(Roo.bootstrap.HtmlEditor.ToolbarStandard, Roo.bootstrap.Navbar, {
15541 editorcore : false,
15546 "h1","h2","h3","h4","h5","h6",
15548 "abbr", "acronym", "address", "cite", "samp", "var",
15552 onRender : function(ct, position)
15554 // Roo.log("Call onRender: " + this.xtype);
15556 Roo.bootstrap.HtmlEditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
15558 this.el.dom.style.marginBottom = '0';
15560 var editorcore = this.editorcore;
15561 var editor= this.editor;
15564 var btn = function(id,cmd , toggle, handler){
15566 var event = toggle ? 'toggle' : 'click';
15571 xns: Roo.bootstrap,
15574 enableToggle:toggle !== false,
15576 pressed : toggle ? false : null,
15579 a.listeners[toggle ? 'toggle' : 'click'] = function() {
15580 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
15589 xns: Roo.bootstrap,
15590 glyphicon : 'font',
15594 xns: Roo.bootstrap,
15598 Roo.each(this.formats, function(f) {
15599 style.menu.items.push({
15601 xns: Roo.bootstrap,
15602 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
15607 editorcore.insertTag(this.tagname);
15614 children.push(style);
15617 btn('bold',false,true);
15618 btn('italic',false,true);
15619 btn('align-left', 'justifyleft',true);
15620 btn('align-center', 'justifycenter',true);
15621 btn('align-right' , 'justifyright',true);
15622 btn('link', false, false, function(btn) {
15623 //Roo.log("create link?");
15624 var url = prompt(this.createLinkText, this.defaultLinkValue);
15625 if(url && url != 'http:/'+'/'){
15626 this.editorcore.relayCmd('createlink', url);
15629 btn('list','insertunorderedlist',true);
15630 btn('pencil', false,true, function(btn){
15633 this.toggleSourceEdit(btn.pressed);
15639 xns: Roo.bootstrap,
15644 xns: Roo.bootstrap,
15649 cog.menu.items.push({
15651 xns: Roo.bootstrap,
15652 html : Clean styles,
15657 editorcore.insertTag(this.tagname);
15666 this.xtype = 'Navbar';
15668 for(var i=0;i< children.length;i++) {
15670 this.buttons.add(this.addxtypeChild(children[i]));
15674 editor.on('editorevent', this.updateToolbar, this);
15676 onBtnClick : function(id)
15678 this.editorcore.relayCmd(id);
15679 this.editorcore.focus();
15683 * Protected method that will not generally be called directly. It triggers
15684 * a toolbar update by reading the markup state of the current selection in the editor.
15686 updateToolbar: function(){
15688 if(!this.editorcore.activated){
15689 this.editor.onFirstFocus(); // is this neeed?
15693 var btns = this.buttons;
15694 var doc = this.editorcore.doc;
15695 btns.get('bold').setActive(doc.queryCommandState('bold'));
15696 btns.get('italic').setActive(doc.queryCommandState('italic'));
15697 //btns.get('underline').setActive(doc.queryCommandState('underline'));
15699 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
15700 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
15701 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
15703 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
15704 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
15707 var ans = this.editorcore.getAllAncestors();
15708 if (this.formatCombo) {
15711 var store = this.formatCombo.store;
15712 this.formatCombo.setValue("");
15713 for (var i =0; i < ans.length;i++) {
15714 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
15716 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
15724 // hides menus... - so this cant be on a menu...
15725 Roo.bootstrap.MenuMgr.hideAll();
15727 Roo.bootstrap.MenuMgr.hideAll();
15728 //this.editorsyncValue();
15730 onFirstFocus: function() {
15731 this.buttons.each(function(item){
15735 toggleSourceEdit : function(sourceEditMode){
15738 if(sourceEditMode){
15739 Roo.log("disabling buttons");
15740 this.buttons.each( function(item){
15741 if(item.cmd != 'pencil'){
15747 Roo.log("enabling buttons");
15748 if(this.editorcore.initialized){
15749 this.buttons.each( function(item){
15755 Roo.log("calling toggole on editor");
15756 // tell the editor that it's been pressed..
15757 this.editor.toggleSourceEdit(sourceEditMode);
15767 * @class Roo.bootstrap.Table.AbstractSelectionModel
15768 * @extends Roo.util.Observable
15769 * Abstract base class for grid SelectionModels. It provides the interface that should be
15770 * implemented by descendant classes. This class should not be directly instantiated.
15773 Roo.bootstrap.Table.AbstractSelectionModel = function(){
15774 this.locked = false;
15775 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
15779 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
15780 /** @ignore Called by the grid automatically. Do not call directly. */
15781 init : function(grid){
15787 * Locks the selections.
15790 this.locked = true;
15794 * Unlocks the selections.
15796 unlock : function(){
15797 this.locked = false;
15801 * Returns true if the selections are locked.
15802 * @return {Boolean}
15804 isLocked : function(){
15805 return this.locked;
15809 * @class Roo.bootstrap.Table.ColumnModel
15810 * @extends Roo.util.Observable
15811 * This is the default implementation of a ColumnModel used by the bootstrap table. It defines
15812 * the columns in the table.
15815 * @param {Object} config An Array of column config objects. See this class's
15816 * config objects for details.
15818 Roo.bootstrap.Table.ColumnModel = function(config){
15820 * The config passed into the constructor
15822 this.config = config;
15825 // if no id, create one
15826 // if the column does not have a dataIndex mapping,
15827 // map it to the order it is in the config
15828 for(var i = 0, len = config.length; i < len; i++){
15830 if(typeof c.dataIndex == "undefined"){
15833 if(typeof c.renderer == "string"){
15834 c.renderer = Roo.util.Format[c.renderer];
15836 if(typeof c.id == "undefined"){
15839 // if(c.editor && c.editor.xtype){
15840 // c.editor = Roo.factory(c.editor, Roo.grid);
15842 // if(c.editor && c.editor.isFormField){
15843 // c.editor = new Roo.grid.GridEditor(c.editor);
15846 this.lookup[c.id] = c;
15850 * The width of columns which have no width specified (defaults to 100)
15853 this.defaultWidth = 100;
15856 * Default sortable of columns which have no sortable specified (defaults to false)
15859 this.defaultSortable = false;
15863 * @event widthchange
15864 * Fires when the width of a column changes.
15865 * @param {ColumnModel} this
15866 * @param {Number} columnIndex The column index
15867 * @param {Number} newWidth The new width
15869 "widthchange": true,
15871 * @event headerchange
15872 * Fires when the text of a header changes.
15873 * @param {ColumnModel} this
15874 * @param {Number} columnIndex The column index
15875 * @param {Number} newText The new header text
15877 "headerchange": true,
15879 * @event hiddenchange
15880 * Fires when a column is hidden or "unhidden".
15881 * @param {ColumnModel} this
15882 * @param {Number} columnIndex The column index
15883 * @param {Boolean} hidden true if hidden, false otherwise
15885 "hiddenchange": true,
15887 * @event columnmoved
15888 * Fires when a column is moved.
15889 * @param {ColumnModel} this
15890 * @param {Number} oldIndex
15891 * @param {Number} newIndex
15893 "columnmoved" : true,
15895 * @event columlockchange
15896 * Fires when a column's locked state is changed
15897 * @param {ColumnModel} this
15898 * @param {Number} colIndex
15899 * @param {Boolean} locked true if locked
15901 "columnlockchange" : true
15903 Roo.bootstrap.Table.ColumnModel.superclass.constructor.call(this);
15905 Roo.extend(Roo.bootstrap.Table.ColumnModel, Roo.util.Observable, {
15907 * @cfg {String} header The header text to display in the Grid view.
15910 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
15911 * {@link Roo.data.Record} definition from which to draw the column's value. If not
15912 * specified, the column's index is used as an index into the Record's data Array.
15915 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
15916 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
15919 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
15920 * Defaults to the value of the {@link #defaultSortable} property.
15921 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
15924 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
15927 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
15930 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
15933 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
15936 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
15937 * given the cell's data value. See {@link #setRenderer}. If not specified, the
15938 * default renderer uses the raw data value.
15941 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
15945 * Returns the id of the column at the specified index.
15946 * @param {Number} index The column index
15947 * @return {String} the id
15949 getColumnId : function(index){
15950 return this.config[index].id;
15954 * Returns the column for a specified id.
15955 * @param {String} id The column id
15956 * @return {Object} the column
15958 getColumnById : function(id){
15959 return this.lookup[id];
15964 * Returns the column for a specified dataIndex.
15965 * @param {String} dataIndex The column dataIndex
15966 * @return {Object|Boolean} the column or false if not found
15968 getColumnByDataIndex: function(dataIndex){
15969 var index = this.findColumnIndex(dataIndex);
15970 return index > -1 ? this.config[index] : false;
15974 * Returns the index for a specified column id.
15975 * @param {String} id The column id
15976 * @return {Number} the index, or -1 if not found
15978 getIndexById : function(id){
15979 for(var i = 0, len = this.config.length; i < len; i++){
15980 if(this.config[i].id == id){
15988 * Returns the index for a specified column dataIndex.
15989 * @param {String} dataIndex The column dataIndex
15990 * @return {Number} the index, or -1 if not found
15993 findColumnIndex : function(dataIndex){
15994 for(var i = 0, len = this.config.length; i < len; i++){
15995 if(this.config[i].dataIndex == dataIndex){
16003 moveColumn : function(oldIndex, newIndex){
16004 var c = this.config[oldIndex];
16005 this.config.splice(oldIndex, 1);
16006 this.config.splice(newIndex, 0, c);
16007 this.dataMap = null;
16008 this.fireEvent("columnmoved", this, oldIndex, newIndex);
16011 isLocked : function(colIndex){
16012 return this.config[colIndex].locked === true;
16015 setLocked : function(colIndex, value, suppressEvent){
16016 if(this.isLocked(colIndex) == value){
16019 this.config[colIndex].locked = value;
16020 if(!suppressEvent){
16021 this.fireEvent("columnlockchange", this, colIndex, value);
16025 getTotalLockedWidth : function(){
16026 var totalWidth = 0;
16027 for(var i = 0; i < this.config.length; i++){
16028 if(this.isLocked(i) && !this.isHidden(i)){
16029 this.totalWidth += this.getColumnWidth(i);
16035 getLockedCount : function(){
16036 for(var i = 0, len = this.config.length; i < len; i++){
16037 if(!this.isLocked(i)){
16044 * Returns the number of columns.
16047 getColumnCount : function(visibleOnly){
16048 if(visibleOnly === true){
16050 for(var i = 0, len = this.config.length; i < len; i++){
16051 if(!this.isHidden(i)){
16057 return this.config.length;
16061 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
16062 * @param {Function} fn
16063 * @param {Object} scope (optional)
16064 * @return {Array} result
16066 getColumnsBy : function(fn, scope){
16068 for(var i = 0, len = this.config.length; i < len; i++){
16069 var c = this.config[i];
16070 if(fn.call(scope||this, c, i) === true){
16078 * Returns true if the specified column is sortable.
16079 * @param {Number} col The column index
16080 * @return {Boolean}
16082 isSortable : function(col){
16083 if(typeof this.config[col].sortable == "undefined"){
16084 return this.defaultSortable;
16086 return this.config[col].sortable;
16090 * Returns the rendering (formatting) function defined for the column.
16091 * @param {Number} col The column index.
16092 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
16094 getRenderer : function(col){
16095 if(!this.config[col].renderer){
16096 return Roo.bootstrap.Table.ColumnModel.defaultRenderer;
16098 return this.config[col].renderer;
16102 * Sets the rendering (formatting) function for a column.
16103 * @param {Number} col The column index
16104 * @param {Function} fn The function to use to process the cell's raw data
16105 * to return HTML markup for the grid view. The render function is called with
16106 * the following parameters:<ul>
16107 * <li>Data value.</li>
16108 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
16109 * <li>css A CSS style string to apply to the table cell.</li>
16110 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
16111 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
16112 * <li>Row index</li>
16113 * <li>Column index</li>
16114 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
16116 setRenderer : function(col, fn){
16117 this.config[col].renderer = fn;
16121 * Returns the width for the specified column.
16122 * @param {Number} col The column index
16125 getColumnWidth : function(col){
16126 return this.config[col].width * 1 || this.defaultWidth;
16130 * Sets the width for a column.
16131 * @param {Number} col The column index
16132 * @param {Number} width The new width
16134 setColumnWidth : function(col, width, suppressEvent){
16135 this.config[col].width = width;
16136 this.totalWidth = null;
16137 if(!suppressEvent){
16138 this.fireEvent("widthchange", this, col, width);
16143 * Returns the total width of all columns.
16144 * @param {Boolean} includeHidden True to include hidden column widths
16147 getTotalWidth : function(includeHidden){
16148 if(!this.totalWidth){
16149 this.totalWidth = 0;
16150 for(var i = 0, len = this.config.length; i < len; i++){
16151 if(includeHidden || !this.isHidden(i)){
16152 this.totalWidth += this.getColumnWidth(i);
16156 return this.totalWidth;
16160 * Returns the header for the specified column.
16161 * @param {Number} col The column index
16164 getColumnHeader : function(col){
16165 return this.config[col].header;
16169 * Sets the header for a column.
16170 * @param {Number} col The column index
16171 * @param {String} header The new header
16173 setColumnHeader : function(col, header){
16174 this.config[col].header = header;
16175 this.fireEvent("headerchange", this, col, header);
16179 * Returns the tooltip for the specified column.
16180 * @param {Number} col The column index
16183 getColumnTooltip : function(col){
16184 return this.config[col].tooltip;
16187 * Sets the tooltip for a column.
16188 * @param {Number} col The column index
16189 * @param {String} tooltip The new tooltip
16191 setColumnTooltip : function(col, tooltip){
16192 this.config[col].tooltip = tooltip;
16196 * Returns the dataIndex for the specified column.
16197 * @param {Number} col The column index
16200 getDataIndex : function(col){
16201 return this.config[col].dataIndex;
16205 * Sets the dataIndex for a column.
16206 * @param {Number} col The column index
16207 * @param {Number} dataIndex The new dataIndex
16209 setDataIndex : function(col, dataIndex){
16210 this.config[col].dataIndex = dataIndex;
16216 * Returns true if the cell is editable.
16217 * @param {Number} colIndex The column index
16218 * @param {Number} rowIndex The row index
16219 * @return {Boolean}
16221 isCellEditable : function(colIndex, rowIndex){
16222 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
16226 * Returns the editor defined for the cell/column.
16227 * return false or null to disable editing.
16228 * @param {Number} colIndex The column index
16229 * @param {Number} rowIndex The row index
16232 getCellEditor : function(colIndex, rowIndex){
16233 return this.config[colIndex].editor;
16237 * Sets if a column is editable.
16238 * @param {Number} col The column index
16239 * @param {Boolean} editable True if the column is editable
16241 setEditable : function(col, editable){
16242 this.config[col].editable = editable;
16247 * Returns true if the column is hidden.
16248 * @param {Number} colIndex The column index
16249 * @return {Boolean}
16251 isHidden : function(colIndex){
16252 return this.config[colIndex].hidden;
16257 * Returns true if the column width cannot be changed
16259 isFixed : function(colIndex){
16260 return this.config[colIndex].fixed;
16264 * Returns true if the column can be resized
16265 * @return {Boolean}
16267 isResizable : function(colIndex){
16268 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
16271 * Sets if a column is hidden.
16272 * @param {Number} colIndex The column index
16273 * @param {Boolean} hidden True if the column is hidden
16275 setHidden : function(colIndex, hidden){
16276 this.config[colIndex].hidden = hidden;
16277 this.totalWidth = null;
16278 this.fireEvent("hiddenchange", this, colIndex, hidden);
16282 * Sets the editor for a column.
16283 * @param {Number} col The column index
16284 * @param {Object} editor The editor object
16286 setEditor : function(col, editor){
16287 this.config[col].editor = editor;
16291 Roo.bootstrap.Table.ColumnModel.defaultRenderer = function(value){
16292 if(typeof value == "string" && value.length < 1){
16298 // Alias for backwards compatibility
16299 Roo.bootstrap.Table.DefaultColumnModel = Roo.bootstrap.Table.ColumnModel;
16302 * @extends Roo.bootstrap.Table.AbstractSelectionModel
16303 * @class Roo.bootstrap.Table.RowSelectionModel
16304 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
16305 * It supports multiple selections and keyboard selection/navigation.
16307 * @param {Object} config
16310 Roo.bootstrap.Table.RowSelectionModel = function(config){
16311 Roo.apply(this, config);
16312 this.selections = new Roo.util.MixedCollection(false, function(o){
16317 this.lastActive = false;
16321 * @event selectionchange
16322 * Fires when the selection changes
16323 * @param {SelectionModel} this
16325 "selectionchange" : true,
16327 * @event afterselectionchange
16328 * Fires after the selection changes (eg. by key press or clicking)
16329 * @param {SelectionModel} this
16331 "afterselectionchange" : true,
16333 * @event beforerowselect
16334 * Fires when a row is selected being selected, return false to cancel.
16335 * @param {SelectionModel} this
16336 * @param {Number} rowIndex The selected index
16337 * @param {Boolean} keepExisting False if other selections will be cleared
16339 "beforerowselect" : true,
16342 * Fires when a row is selected.
16343 * @param {SelectionModel} this
16344 * @param {Number} rowIndex The selected index
16345 * @param {Roo.data.Record} r The record
16347 "rowselect" : true,
16349 * @event rowdeselect
16350 * Fires when a row is deselected.
16351 * @param {SelectionModel} this
16352 * @param {Number} rowIndex The selected index
16354 "rowdeselect" : true
16356 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
16357 this.locked = false;
16360 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
16362 * @cfg {Boolean} singleSelect
16363 * True to allow selection of only one row at a time (defaults to false)
16365 singleSelect : false,
16368 initEvents : function(){
16370 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
16371 this.grid.on("mousedown", this.handleMouseDown, this);
16372 }else{ // allow click to work like normal
16373 this.grid.on("rowclick", this.handleDragableRowClick, this);
16376 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
16377 "up" : function(e){
16379 this.selectPrevious(e.shiftKey);
16380 }else if(this.last !== false && this.lastActive !== false){
16381 var last = this.last;
16382 this.selectRange(this.last, this.lastActive-1);
16383 this.grid.getView().focusRow(this.lastActive);
16384 if(last !== false){
16388 this.selectFirstRow();
16390 this.fireEvent("afterselectionchange", this);
16392 "down" : function(e){
16394 this.selectNext(e.shiftKey);
16395 }else if(this.last !== false && this.lastActive !== false){
16396 var last = this.last;
16397 this.selectRange(this.last, this.lastActive+1);
16398 this.grid.getView().focusRow(this.lastActive);
16399 if(last !== false){
16403 this.selectFirstRow();
16405 this.fireEvent("afterselectionchange", this);
16410 var view = this.grid.view;
16411 view.on("refresh", this.onRefresh, this);
16412 view.on("rowupdated", this.onRowUpdated, this);
16413 view.on("rowremoved", this.onRemove, this);
16417 onRefresh : function(){
16418 var ds = this.grid.dataSource, i, v = this.grid.view;
16419 var s = this.selections;
16420 s.each(function(r){
16421 if((i = ds.indexOfId(r.id)) != -1){
16430 onRemove : function(v, index, r){
16431 this.selections.remove(r);
16435 onRowUpdated : function(v, index, r){
16436 if(this.isSelected(r)){
16437 v.onRowSelect(index);
16443 * @param {Array} records The records to select
16444 * @param {Boolean} keepExisting (optional) True to keep existing selections
16446 selectRecords : function(records, keepExisting){
16448 this.clearSelections();
16450 var ds = this.grid.dataSource;
16451 for(var i = 0, len = records.length; i < len; i++){
16452 this.selectRow(ds.indexOf(records[i]), true);
16457 * Gets the number of selected rows.
16460 getCount : function(){
16461 return this.selections.length;
16465 * Selects the first row in the grid.
16467 selectFirstRow : function(){
16472 * Select the last row.
16473 * @param {Boolean} keepExisting (optional) True to keep existing selections
16475 selectLastRow : function(keepExisting){
16476 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
16480 * Selects the row immediately following the last selected row.
16481 * @param {Boolean} keepExisting (optional) True to keep existing selections
16483 selectNext : function(keepExisting){
16484 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
16485 this.selectRow(this.last+1, keepExisting);
16486 this.grid.getView().focusRow(this.last);
16491 * Selects the row that precedes the last selected row.
16492 * @param {Boolean} keepExisting (optional) True to keep existing selections
16494 selectPrevious : function(keepExisting){
16496 this.selectRow(this.last-1, keepExisting);
16497 this.grid.getView().focusRow(this.last);
16502 * Returns the selected records
16503 * @return {Array} Array of selected records
16505 getSelections : function(){
16506 return [].concat(this.selections.items);
16510 * Returns the first selected record.
16513 getSelected : function(){
16514 return this.selections.itemAt(0);
16519 * Clears all selections.
16521 clearSelections : function(fast){
16522 if(this.locked) return;
16524 var ds = this.grid.dataSource;
16525 var s = this.selections;
16526 s.each(function(r){
16527 this.deselectRow(ds.indexOfId(r.id));
16531 this.selections.clear();
16538 * Selects all rows.
16540 selectAll : function(){
16541 if(this.locked) return;
16542 this.selections.clear();
16543 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
16544 this.selectRow(i, true);
16549 * Returns True if there is a selection.
16550 * @return {Boolean}
16552 hasSelection : function(){
16553 return this.selections.length > 0;
16557 * Returns True if the specified row is selected.
16558 * @param {Number/Record} record The record or index of the record to check
16559 * @return {Boolean}
16561 isSelected : function(index){
16562 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
16563 return (r && this.selections.key(r.id) ? true : false);
16567 * Returns True if the specified record id is selected.
16568 * @param {String} id The id of record to check
16569 * @return {Boolean}
16571 isIdSelected : function(id){
16572 return (this.selections.key(id) ? true : false);
16576 handleMouseDown : function(e, t){
16577 var view = this.grid.getView(), rowIndex;
16578 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
16581 if(e.shiftKey && this.last !== false){
16582 var last = this.last;
16583 this.selectRange(last, rowIndex, e.ctrlKey);
16584 this.last = last; // reset the last
16585 view.focusRow(rowIndex);
16587 var isSelected = this.isSelected(rowIndex);
16588 if(e.button !== 0 && isSelected){
16589 view.focusRow(rowIndex);
16590 }else if(e.ctrlKey && isSelected){
16591 this.deselectRow(rowIndex);
16592 }else if(!isSelected){
16593 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
16594 view.focusRow(rowIndex);
16597 this.fireEvent("afterselectionchange", this);
16600 handleDragableRowClick : function(grid, rowIndex, e)
16602 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
16603 this.selectRow(rowIndex, false);
16604 grid.view.focusRow(rowIndex);
16605 this.fireEvent("afterselectionchange", this);
16610 * Selects multiple rows.
16611 * @param {Array} rows Array of the indexes of the row to select
16612 * @param {Boolean} keepExisting (optional) True to keep existing selections
16614 selectRows : function(rows, keepExisting){
16616 this.clearSelections();
16618 for(var i = 0, len = rows.length; i < len; i++){
16619 this.selectRow(rows[i], true);
16624 * Selects a range of rows. All rows in between startRow and endRow are also selected.
16625 * @param {Number} startRow The index of the first row in the range
16626 * @param {Number} endRow The index of the last row in the range
16627 * @param {Boolean} keepExisting (optional) True to retain existing selections
16629 selectRange : function(startRow, endRow, keepExisting){
16630 if(this.locked) return;
16632 this.clearSelections();
16634 if(startRow <= endRow){
16635 for(var i = startRow; i <= endRow; i++){
16636 this.selectRow(i, true);
16639 for(var i = startRow; i >= endRow; i--){
16640 this.selectRow(i, true);
16646 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
16647 * @param {Number} startRow The index of the first row in the range
16648 * @param {Number} endRow The index of the last row in the range
16650 deselectRange : function(startRow, endRow, preventViewNotify){
16651 if(this.locked) return;
16652 for(var i = startRow; i <= endRow; i++){
16653 this.deselectRow(i, preventViewNotify);
16659 * @param {Number} row The index of the row to select
16660 * @param {Boolean} keepExisting (optional) True to keep existing selections
16662 selectRow : function(index, keepExisting, preventViewNotify){
16663 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
16664 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
16665 if(!keepExisting || this.singleSelect){
16666 this.clearSelections();
16668 var r = this.grid.dataSource.getAt(index);
16669 this.selections.add(r);
16670 this.last = this.lastActive = index;
16671 if(!preventViewNotify){
16672 this.grid.getView().onRowSelect(index);
16674 this.fireEvent("rowselect", this, index, r);
16675 this.fireEvent("selectionchange", this);
16681 * @param {Number} row The index of the row to deselect
16683 deselectRow : function(index, preventViewNotify){
16684 if(this.locked) return;
16685 if(this.last == index){
16688 if(this.lastActive == index){
16689 this.lastActive = false;
16691 var r = this.grid.dataSource.getAt(index);
16692 this.selections.remove(r);
16693 if(!preventViewNotify){
16694 this.grid.getView().onRowDeselect(index);
16696 this.fireEvent("rowdeselect", this, index);
16697 this.fireEvent("selectionchange", this);
16701 restoreLast : function(){
16703 this.last = this._last;
16708 acceptsNav : function(row, col, cm){
16709 return !cm.isHidden(col) && cm.isCellEditable(col, row);
16713 onEditorKey : function(field, e){
16714 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
16719 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
16721 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
16723 }else if(k == e.ENTER && !e.ctrlKey){
16727 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
16729 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
16731 }else if(k == e.ESC){
16735 g.startEditing(newCell[0], newCell[1]);
16746 * @class Roo.bootstrap.MessageBar
16747 * @extends Roo.bootstrap.Component
16748 * Bootstrap MessageBar class
16749 * @cfg {String} html contents of the MessageBar
16750 * @cfg {String} weight (info | success | warning | danger) default info
16751 * @cfg {String} beforeClass insert the bar before the given class
16752 * @cfg {Boolean} closable (true | false) default false
16753 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
16756 * Create a new Element
16757 * @param {Object} config The config object
16760 Roo.bootstrap.MessageBar = function(config){
16761 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
16764 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
16770 beforeClass: 'bootstrap-sticky-wrap',
16772 getAutoCreate : function(){
16776 cls: 'alert alert-dismissable alert-' + this.weight,
16781 html: this.html || ''
16787 cfg.cls += ' alert-messages-fixed';
16801 onRender : function(ct, position)
16803 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
16806 var cfg = Roo.apply({}, this.getAutoCreate());
16810 cfg.cls += ' ' + this.cls;
16813 cfg.style = this.style;
16815 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
16817 this.el.setVisibilityMode(Roo.Element.DISPLAY);
16820 this.el.select('>button.close').on('click', this.hide, this);
16826 if (!this.rendered) {
16832 this.fireEvent('show', this);
16838 if (!this.rendered) {
16844 this.fireEvent('hide', this);
16847 update : function()
16849 // var e = this.el.dom.firstChild;
16851 // if(this.closable){
16852 // e = e.nextSibling;
16855 // e.data = this.html || '';
16857 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';