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);
300 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
305 onRender : function(ct, position){
308 //this.el.addClass([this.fieldClass, this.cls]);
326 * @class Roo.bootstrap.ButtonGroup
327 * @extends Roo.bootstrap.Component
328 * Bootstrap ButtonGroup class
329 * @cfg {String} size lg | sm | xs (default empty normal)
330 * @cfg {String} align vertical | justified (default none)
331 * @cfg {String} direction up | down (default down)
332 * @cfg {Boolean} toolbar false | true
333 * @cfg {Boolean} btn true | false
338 * @param {Object} config The config object
341 Roo.bootstrap.ButtonGroup = function(config){
342 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
345 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
353 getAutoCreate : function(){
359 cfg.html = this.html || cfg.html;
370 if (['vertical','justified'].indexOf(this.align)!==-1) {
371 cfg.cls = 'btn-group-' + this.align;
373 if (this.align == 'justified') {
374 console.log(this.items);
378 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
379 cfg.cls += ' btn-group-' + this.size;
382 if (this.direction == 'up') {
383 cfg.cls += ' dropup' ;
399 * @class Roo.bootstrap.Button
400 * @extends Roo.bootstrap.Component
401 * Bootstrap Button class
402 * @cfg {String} html The button content
403 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger | link
404 * @cfg {String} size empty | lg | sm | xs
405 * @cfg {String} tag empty | a | input | submit
406 * @cfg {String} href empty or href
407 * @cfg {Boolean} disabled false | true
408 * @cfg {Boolean} isClose false | true
409 * @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
410 * @cfg {String} badge text for badge
411 * @cfg {String} theme default (or empty) | glow
412 * @cfg {Boolean} inverse false | true
413 * @cfg {Boolean} toggle false | true
414 * @cfg {String} ontext text for on toggle state
415 * @cfg {String} offtext text for off toggle state
416 * @cfg {Boolean} defaulton true | false
417 * @cfg {Boolean} preventDefault (true | false) default true
418 * @cfg {Boolean} removeClass true | false remove the standard class..
419 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
422 * Create a new button
423 * @param {Object} config The config object
427 Roo.bootstrap.Button = function(config){
428 Roo.bootstrap.Button.superclass.constructor.call(this, config);
433 * When a butotn is pressed
434 * @param {Roo.EventObject} e
439 * After the button has been toggles
440 * @param {Roo.EventObject} e
441 * @param {boolean} pressed (also available as button.pressed)
447 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
465 preventDefault: true,
474 getAutoCreate : function(){
482 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
483 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
488 cfg.html = this.html || cfg.html;
490 if (this.toggle == true) {
493 cls: 'slider-frame roo-button',
498 'data-off-text':'OFF',
499 cls: 'slider-button',
505 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
506 cfg.cls += ' '+this.weight;
515 cfg["aria-hidden"] = true;
517 cfg.html = "×";
523 if (this.theme==='default') {
524 cfg.cls = 'btn roo-button';
526 //if (this.parentType != 'Navbar') {
527 this.weight = this.weight.length ? this.weight : 'default';
529 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
531 cfg.cls += ' btn-' + this.weight;
533 } else if (this.theme==='glow') {
536 cfg.cls = 'btn-glow roo-button';
538 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
540 cfg.cls += ' ' + this.weight;
546 this.cls += ' inverse';
551 cfg.cls += ' active';
555 cfg.disabled = 'disabled';
559 Roo.log('changing to ul' );
561 this.glyphicon = 'caret';
564 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
566 //gsRoo.log(this.parentType);
567 if (this.parentType === 'Navbar' && !this.parent().bar) {
568 Roo.log('changing to li?');
577 href : this.href || '#'
580 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
581 cfg.cls += ' dropdown';
588 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
590 if (this.glyphicon) {
591 cfg.html = ' ' + cfg.html;
596 cls: 'glyphicon glyphicon-' + this.glyphicon
606 // cfg.cls='btn roo-button';
610 var value = cfg.html;
615 cls: 'glyphicon glyphicon-' + this.glyphicon,
634 cfg.cls += ' dropdown';
635 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
638 if (cfg.tag !== 'a' && this.href !== '') {
639 throw "Tag must be a to set href.";
640 } else if (this.href.length > 0) {
641 cfg.href = this.href;
644 if(this.removeClass){
649 cfg.target = this.target;
654 initEvents: function() {
655 // Roo.log('init events?');
656 // Roo.log(this.el.dom);
657 if (this.el.hasClass('roo-button')) {
658 this.el.on('click', this.onClick, this);
660 this.el.select('.roo-button').on('click', this.onClick, this);
666 onClick : function(e)
672 Roo.log('button on click ');
673 if(this.preventDefault){
676 if (this.pressed === true || this.pressed === false) {
677 this.pressed = !this.pressed;
678 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
679 this.fireEvent('toggle', this, e, this.pressed);
683 this.fireEvent('click', this, e);
687 * Enables this button
691 this.disabled = false;
692 this.el.removeClass('disabled');
696 * Disable this button
700 this.disabled = true;
701 this.el.addClass('disabled');
704 * sets the active state on/off,
705 * @param {Boolean} state (optional) Force a particular state
707 setActive : function(v) {
709 this.el[v ? 'addClass' : 'removeClass']('active');
712 * toggles the current active state
714 toggleActive : function()
716 var active = this.el.hasClass('active');
717 this.setActive(!active);
734 * @class Roo.bootstrap.Column
735 * @extends Roo.bootstrap.Component
736 * Bootstrap Column class
737 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
738 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
739 * @cfg {Number} md colspan out of 12 for computer-sized screens
740 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
741 * @cfg {String} html content of column.
744 * Create a new Column
745 * @param {Object} config The config object
748 Roo.bootstrap.Column = function(config){
749 Roo.bootstrap.Column.superclass.constructor.call(this, config);
752 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
761 getAutoCreate : function(){
762 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
770 ['xs','sm','md','lg'].map(function(size){
771 if (settings[size]) {
772 cfg.cls += ' col-' + size + '-' + settings[size];
775 if (this.html.length) {
776 cfg.html = this.html;
795 * @class Roo.bootstrap.Container
796 * @extends Roo.bootstrap.Component
797 * Bootstrap Container class
798 * @cfg {Boolean} jumbotron is it a jumbotron element
799 * @cfg {String} html content of element
800 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
801 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
802 * @cfg {String} header content of header (for panel)
803 * @cfg {String} footer content of footer (for panel)
804 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
807 * Create a new Container
808 * @param {Object} config The config object
811 Roo.bootstrap.Container = function(config){
812 Roo.bootstrap.Container.superclass.constructor.call(this, config);
815 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
825 getChildContainer : function() {
831 if (this.panel.length) {
832 return this.el.select('.panel-body',true).first();
839 getAutoCreate : function(){
845 if (this.jumbotron) {
846 cfg.cls = 'jumbotron';
849 cfg.cls = this.cls + '';
852 if (this.sticky.length) {
854 var bd = Roo.get(document.body);
855 if (!bd.hasClass('bootstrap-sticky')) {
856 bd.addClass('bootstrap-sticky');
857 Roo.select('html',true).setStyle('height', '100%');
860 cfg.cls += 'bootstrap-sticky-' + this.sticky;
864 if (this.well.length) {
868 cfg.cls +=' well well-' +this.well;
878 if (this.panel.length) {
879 cfg.cls += ' panel panel-' + this.panel;
881 if (this.header.length) {
884 cls : 'panel-heading',
900 if (this.footer.length) {
902 cls : 'panel-footer',
910 body.html = this.html || cfg.html;
912 if (!cfg.cls.length) {
913 cfg.cls = 'container';
930 * @class Roo.bootstrap.Img
931 * @extends Roo.bootstrap.Component
932 * Bootstrap Img class
933 * @cfg {Boolean} imgResponsive false | true
934 * @cfg {String} border rounded | circle | thumbnail
935 * @cfg {String} src image source
936 * @cfg {String} alt image alternative text
937 * @cfg {String} href a tag href
938 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
942 * @param {Object} config The config object
945 Roo.bootstrap.Img = function(config){
946 Roo.bootstrap.Img.superclass.constructor.call(this, config);
952 * The img click event for the img.
953 * @param {Roo.EventObject} e
959 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
967 getAutoCreate : function(){
971 cls: 'img-responsive',
975 cfg.html = this.html || cfg.html;
977 cfg.src = this.src || cfg.src;
979 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
980 cfg.cls += ' img-' + this.border;
997 a.target = this.target;
1003 return (this.href) ? a : cfg;
1006 initEvents: function() {
1009 this.el.on('click', this.onClick, this);
1013 onClick : function(e)
1015 Roo.log('img onclick');
1016 this.fireEvent('click', this, e);
1029 * @class Roo.bootstrap.Header
1030 * @extends Roo.bootstrap.Component
1031 * Bootstrap Header class
1032 * @cfg {String} html content of header
1033 * @cfg {Number} level (1|2|3|4|5|6) default 1
1036 * Create a new Header
1037 * @param {Object} config The config object
1041 Roo.bootstrap.Header = function(config){
1042 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1045 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1053 getAutoCreate : function(){
1056 tag: 'h' + (1 *this.level),
1057 html: this.html || 'fill in html'
1069 * Ext JS Library 1.1.1
1070 * Copyright(c) 2006-2007, Ext JS, LLC.
1072 * Originally Released Under LGPL - original licence link has changed is not relivant.
1075 * <script type="text/javascript">
1079 * @class Roo.bootstrap.MenuMgr
1080 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1083 Roo.bootstrap.MenuMgr = function(){
1084 var menus, active, groups = {}, attached = false, lastShow = new Date();
1086 // private - called when first menu is created
1089 active = new Roo.util.MixedCollection();
1090 Roo.get(document).addKeyListener(27, function(){
1091 if(active.length > 0){
1099 if(active && active.length > 0){
1100 var c = active.clone();
1110 if(active.length < 1){
1111 Roo.get(document).un("mouseup", onMouseDown);
1119 var last = active.last();
1120 lastShow = new Date();
1123 Roo.get(document).on("mouseup", onMouseDown);
1128 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1129 m.parentMenu.activeChild = m;
1130 }else if(last && last.isVisible()){
1131 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1136 function onBeforeHide(m){
1138 m.activeChild.hide();
1140 if(m.autoHideTimer){
1141 clearTimeout(m.autoHideTimer);
1142 delete m.autoHideTimer;
1147 function onBeforeShow(m){
1148 var pm = m.parentMenu;
1149 if(!pm && !m.allowOtherMenus){
1151 }else if(pm && pm.activeChild && active != m){
1152 pm.activeChild.hide();
1157 function onMouseDown(e){
1158 Roo.log("on MouseDown");
1159 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1167 function onBeforeCheck(mi, state){
1169 var g = groups[mi.group];
1170 for(var i = 0, l = g.length; i < l; i++){
1172 g[i].setChecked(false);
1181 * Hides all menus that are currently visible
1183 hideAll : function(){
1188 register : function(menu){
1192 menus[menu.id] = menu;
1193 menu.on("beforehide", onBeforeHide);
1194 menu.on("hide", onHide);
1195 menu.on("beforeshow", onBeforeShow);
1196 menu.on("show", onShow);
1198 if(g && menu.events["checkchange"]){
1202 groups[g].push(menu);
1203 menu.on("checkchange", onCheck);
1208 * Returns a {@link Roo.menu.Menu} object
1209 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1210 * be used to generate and return a new Menu instance.
1212 get : function(menu){
1213 if(typeof menu == "string"){ // menu id
1215 }else if(menu.events){ // menu instance
1218 /*else if(typeof menu.length == 'number'){ // array of menu items?
1219 return new Roo.bootstrap.Menu({items:menu});
1220 }else{ // otherwise, must be a config
1221 return new Roo.bootstrap.Menu(menu);
1228 unregister : function(menu){
1229 delete menus[menu.id];
1230 menu.un("beforehide", onBeforeHide);
1231 menu.un("hide", onHide);
1232 menu.un("beforeshow", onBeforeShow);
1233 menu.un("show", onShow);
1235 if(g && menu.events["checkchange"]){
1236 groups[g].remove(menu);
1237 menu.un("checkchange", onCheck);
1242 registerCheckable : function(menuItem){
1243 var g = menuItem.group;
1248 groups[g].push(menuItem);
1249 menuItem.on("beforecheckchange", onBeforeCheck);
1254 unregisterCheckable : function(menuItem){
1255 var g = menuItem.group;
1257 groups[g].remove(menuItem);
1258 menuItem.un("beforecheckchange", onBeforeCheck);
1270 * @class Roo.bootstrap.Menu
1271 * @extends Roo.bootstrap.Component
1272 * Bootstrap Menu class - container for MenuItems
1273 * @cfg {String} type type of menu
1277 * @param {Object} config The config object
1281 Roo.bootstrap.Menu = function(config){
1282 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1283 if (this.registerMenu) {
1284 Roo.bootstrap.MenuMgr.register(this);
1289 * Fires before this menu is displayed
1290 * @param {Roo.menu.Menu} this
1295 * Fires before this menu is hidden
1296 * @param {Roo.menu.Menu} this
1301 * Fires after this menu is displayed
1302 * @param {Roo.menu.Menu} this
1307 * Fires after this menu is hidden
1308 * @param {Roo.menu.Menu} this
1313 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1314 * @param {Roo.menu.Menu} this
1315 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1316 * @param {Roo.EventObject} e
1321 * Fires when the mouse is hovering over this menu
1322 * @param {Roo.menu.Menu} this
1323 * @param {Roo.EventObject} e
1324 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1329 * Fires when the mouse exits this menu
1330 * @param {Roo.menu.Menu} this
1331 * @param {Roo.EventObject} e
1332 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1337 * Fires when a menu item contained in this menu is clicked
1338 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1339 * @param {Roo.EventObject} e
1343 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1346 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1350 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1353 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1355 registerMenu : true,
1357 menuItems :false, // stores the menu items..
1363 getChildContainer : function() {
1367 getAutoCreate : function(){
1369 //if (['right'].indexOf(this.align)!==-1) {
1370 // cfg.cn[1].cls += ' pull-right'
1374 cls : 'dropdown-menu' ,
1375 style : 'z-index:1000'
1379 if (this.type === 'submenu') {
1380 cfg.cls = 'submenu active'
1385 initEvents : function() {
1387 // Roo.log("ADD event");
1388 // Roo.log(this.triggerEl.dom);
1389 this.triggerEl.on('click', this.onTriggerPress, this);
1390 this.triggerEl.addClass('dropdown-toggle');
1391 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1393 this.el.on("mouseover", this.onMouseOver, this);
1394 this.el.on("mouseout", this.onMouseOut, this);
1398 findTargetItem : function(e){
1399 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1403 //Roo.log(t); Roo.log(t.id);
1405 //Roo.log(this.menuitems);
1406 return this.menuitems.get(t.id);
1408 //return this.items.get(t.menuItemId);
1413 onClick : function(e){
1414 Roo.log("menu.onClick");
1415 var t = this.findTargetItem(e);
1421 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1422 if(t == this.activeItem && t.shouldDeactivate(e)){
1423 this.activeItem.deactivate();
1424 delete this.activeItem;
1428 this.setActiveItem(t, true);
1435 Roo.log('pass click event');
1439 this.fireEvent("click", this, t, e);
1443 onMouseOver : function(e){
1444 var t = this.findTargetItem(e);
1447 // if(t.canActivate && !t.disabled){
1448 // this.setActiveItem(t, true);
1452 this.fireEvent("mouseover", this, e, t);
1454 isVisible : function(){
1455 return !this.hidden;
1457 onMouseOut : function(e){
1458 var t = this.findTargetItem(e);
1461 // if(t == this.activeItem && t.shouldDeactivate(e)){
1462 // this.activeItem.deactivate();
1463 // delete this.activeItem;
1466 this.fireEvent("mouseout", this, e, t);
1471 * Displays this menu relative to another element
1472 * @param {String/HTMLElement/Roo.Element} element The element to align to
1473 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1474 * the element (defaults to this.defaultAlign)
1475 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1477 show : function(el, pos, parentMenu){
1478 this.parentMenu = parentMenu;
1482 this.fireEvent("beforeshow", this);
1483 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1486 * Displays this menu at a specific xy position
1487 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1488 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1490 showAt : function(xy, parentMenu, /* private: */_e){
1491 this.parentMenu = parentMenu;
1496 this.fireEvent("beforeshow", this);
1498 //xy = this.el.adjustForConstraints(xy);
1500 //this.el.setXY(xy);
1502 this.hideMenuItems();
1503 this.hidden = false;
1504 this.triggerEl.addClass('open');
1506 this.fireEvent("show", this);
1512 this.doFocus.defer(50, this);
1516 doFocus : function(){
1518 this.focusEl.focus();
1523 * Hides this menu and optionally all parent menus
1524 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1526 hide : function(deep){
1528 this.hideMenuItems();
1529 if(this.el && this.isVisible()){
1530 this.fireEvent("beforehide", this);
1531 if(this.activeItem){
1532 this.activeItem.deactivate();
1533 this.activeItem = null;
1535 this.triggerEl.removeClass('open');;
1537 this.fireEvent("hide", this);
1539 if(deep === true && this.parentMenu){
1540 this.parentMenu.hide(true);
1544 onTriggerPress : function(e)
1547 Roo.log('trigger press');
1548 //Roo.log(e.getTarget());
1549 // Roo.log(this.triggerEl.dom);
1550 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1553 if (this.isVisible()) {
1557 this.show(this.triggerEl, false, false);
1566 hideMenuItems : function()
1568 //$(backdrop).remove()
1569 Roo.select('.open',true).each(function(aa) {
1571 aa.removeClass('open');
1572 //var parent = getParent($(this))
1573 //var relatedTarget = { relatedTarget: this }
1575 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1576 //if (e.isDefaultPrevented()) return
1577 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1580 addxtypeChild : function (tree, cntr) {
1581 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1583 this.menuitems.add(comp);
1604 * @class Roo.bootstrap.MenuItem
1605 * @extends Roo.bootstrap.Component
1606 * Bootstrap MenuItem class
1607 * @cfg {String} html the menu label
1608 * @cfg {String} href the link
1609 * @cfg {Boolean} preventDefault (true | false) default true
1613 * Create a new MenuItem
1614 * @param {Object} config The config object
1618 Roo.bootstrap.MenuItem = function(config){
1619 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1624 * The raw click event for the entire grid.
1625 * @param {Roo.EventObject} e
1631 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1635 preventDefault: true,
1637 getAutoCreate : function(){
1640 cls: 'dropdown-menu-item',
1650 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1651 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1655 initEvents: function() {
1657 //this.el.select('a').on('click', this.onClick, this);
1660 onClick : function(e)
1662 Roo.log('item on click ');
1663 //if(this.preventDefault){
1664 // e.preventDefault();
1666 //this.parent().hideMenuItems();
1668 this.fireEvent('click', this, e);
1687 * @class Roo.bootstrap.MenuSeparator
1688 * @extends Roo.bootstrap.Component
1689 * Bootstrap MenuSeparator class
1692 * Create a new MenuItem
1693 * @param {Object} config The config object
1697 Roo.bootstrap.MenuSeparator = function(config){
1698 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1701 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1703 getAutoCreate : function(){
1718 <div class="modal fade">
1719 <div class="modal-dialog">
1720 <div class="modal-content">
1721 <div class="modal-header">
1722 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1723 <h4 class="modal-title">Modal title</h4>
1725 <div class="modal-body">
1726 <p>One fine body…</p>
1728 <div class="modal-footer">
1729 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1730 <button type="button" class="btn btn-primary">Save changes</button>
1732 </div><!-- /.modal-content -->
1733 </div><!-- /.modal-dialog -->
1734 </div><!-- /.modal -->
1744 * @class Roo.bootstrap.Modal
1745 * @extends Roo.bootstrap.Component
1746 * Bootstrap Modal class
1747 * @cfg {String} title Title of dialog
1748 * @cfg {Array} buttons Array of buttons or standard button set..
1751 * Create a new Modal Dialog
1752 * @param {Object} config The config object
1755 Roo.bootstrap.Modal = function(config){
1756 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1761 * The raw btnclick event for the button
1762 * @param {Roo.EventObject} e
1768 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1770 title : 'test dialog',
1774 onRender : function(ct, position)
1776 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1779 var cfg = Roo.apply({}, this.getAutoCreate());
1782 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1784 //if (!cfg.name.length) {
1788 cfg.cls += ' ' + this.cls;
1791 cfg.style = this.style;
1793 this.el = Roo.get(document.body).createChild(cfg, position);
1795 //var type = this.el.dom.type;
1797 if(this.tabIndex !== undefined){
1798 this.el.dom.setAttribute('tabIndex', this.tabIndex);
1803 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1804 this.maskEl.enableDisplayMode("block");
1806 //this.el.addClass("x-dlg-modal");
1809 Roo.each(this.buttons, function(bb) {
1810 b = Roo.apply({}, bb);
1811 b.xns = b.xns || Roo.bootstrap;
1812 b.xtype = b.xtype || 'Button';
1813 if (typeof(b.listeners) == 'undefined') {
1814 b.listeners = { click : this.onButtonClick.createDelegate(this) };
1817 var btn = Roo.factory(b);
1819 btn.onRender(this.el.select('.modal-footer').first());
1823 // render the children.
1826 if(typeof(this.items) != 'undefined'){
1827 var items = this.items;
1830 for(var i =0;i < items.length;i++) {
1831 nitems.push(this.addxtype(Roo.apply({}, items[i])));
1835 this.items = nitems;
1837 //this.el.addClass([this.fieldClass, this.cls]);
1840 getAutoCreate : function(){
1845 html : this.html || ''
1853 cls: "modal-dialog",
1856 cls : "modal-content",
1859 cls : 'modal-header',
1868 cls : 'modal-title',
1876 cls : 'modal-footer'
1892 getChildContainer : function() {
1894 return this.el.select('.modal-body',true).first();
1897 getButtonContainer : function() {
1898 return this.el.select('.modal-footer',true).first();
1901 initEvents : function()
1903 this.el.select('.modal-header .close').on('click', this.hide, this);
1905 // this.addxtype(this);
1909 if (!this.rendered) {
1913 this.el.addClass('on');
1914 this.el.removeClass('fade');
1915 this.el.setStyle('display', 'block');
1916 Roo.get(document.body).addClass("x-body-masked");
1917 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
1919 this.el.setStyle('zIndex', '10001');
1920 this.fireEvent('show', this);
1926 Roo.log('Modal hide?!');
1928 Roo.get(document.body).removeClass("x-body-masked");
1929 this.el.removeClass('on');
1930 this.el.addClass('fade');
1931 this.el.setStyle('display', 'none');
1932 this.fireEvent('hide', this);
1934 onButtonClick: function(btn,e)
1937 this.fireEvent('btnclick', btn.name, e);
1942 Roo.apply(Roo.bootstrap.Modal, {
1944 * Button config that displays a single OK button
1953 * Button config that displays Yes and No buttons
1969 * Button config that displays OK and Cancel buttons
1984 * Button config that displays Yes, No and Cancel buttons
2011 * @class Roo.bootstrap.Navbar
2012 * @extends Roo.bootstrap.Component
2013 * Bootstrap Navbar class
2014 * @cfg {Boolean} sidebar has side bar
2015 * @cfg {Boolean} bar is a bar?
2016 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
2017 * @cfg {String} brand what is brand
2018 * @cfg {Boolean} inverse is inverted color
2019 * @cfg {String} type (nav | pills | tabs)
2020 * @cfg {Boolean} arrangement stacked | justified
2021 * @cfg {String} align (left | right) alignment
2022 * @cfg {String} brand_href href of the brand
2023 * @cfg {Boolean} main (true|false) main nav bar? default false
2024 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
2028 * Create a new Navbar
2029 * @param {Object} config The config object
2033 Roo.bootstrap.Navbar = function(config){
2034 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2039 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2058 getAutoCreate : function(){
2063 if (this.sidebar === true) {
2071 if (this.bar === true) {
2079 cls: 'navbar-header',
2084 cls: 'navbar-toggle',
2085 'data-toggle': 'collapse',
2090 html: 'Toggle navigation'
2110 cls: 'collapse navbar-collapse'
2115 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
2117 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
2118 cfg.cls += ' navbar-' + this.position;
2119 cfg.tag = this.position == 'fixed-bottom' ? 'footer' : 'header';
2122 if (this.brand !== '') {
2125 href: this.brand_href ? this.brand_href : '#',
2126 cls: 'navbar-brand',
2134 cfg.cls += ' main-nav';
2140 } else if (this.bar === false) {
2143 Roo.log('Property \'bar\' in of Navbar must be either true or false')
2153 if (['tabs','pills'].indexOf(this.type)!==-1) {
2154 cfg.cn[0].cls += ' nav-' + this.type
2156 if (this.type!=='nav') {
2157 Roo.log('nav type must be nav/tabs/pills')
2159 cfg.cn[0].cls += ' navbar-nav'
2162 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
2163 cfg.cn[0].cls += ' nav-' + this.arrangement;
2166 if (this.align === 'right') {
2167 cfg.cn[0].cls += ' navbar-right';
2170 cfg.cls += ' navbar-inverse';
2178 initEvents :function ()
2180 //Roo.log(this.el.select('.navbar-toggle',true));
2181 this.el.select('.navbar-toggle',true).on('click', function() {
2182 // Roo.log('click');
2183 this.el.select('.navbar-collapse',true).toggleClass('in');
2191 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2193 var size = this.el.getSize();
2194 this.maskEl.setSize(size.width, size.height);
2195 this.maskEl.enableDisplayMode("block");
2204 getChildContainer : function()
2206 if (this.bar === true) {
2207 return this.el.select('.collapse',true).first();
2239 * @class Roo.bootstrap.NavGroup
2240 * @extends Roo.bootstrap.Component
2241 * Bootstrap NavGroup class
2242 * @cfg {String} align left | right
2243 * @cfg {Boolean} inverse false | true
2244 * @cfg {String} type (nav|pills|tab) default nav
2245 * @cfg {String} navId - reference Id for navbar.
2249 * Create a new nav group
2250 * @param {Object} config The config object
2253 Roo.bootstrap.NavGroup = function(config){
2254 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
2256 Roo.bootstrap.NavGroup.register(this);
2260 * Fires when the active item changes
2261 * @param {Roo.bootstrap.NavGroup} this
2262 * @param {Roo.bootstrap.Navbar.Item} item The item selected
2263 * @param {Roo.bootstrap.Navbar.Item} item The previously selected item
2270 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
2281 getAutoCreate : function()
2283 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
2290 if (['tabs','pills'].indexOf(this.type)!==-1) {
2291 cfg.cls += ' nav-' + this.type
2293 if (this.type!=='nav') {
2294 Roo.log('nav type must be nav/tabs/pills')
2296 cfg.cls += ' navbar-nav'
2299 if (this.parent().sidebar === true) {
2302 cls: 'dashboard-menu'
2308 if (this.form === true) {
2314 if (this.align === 'right') {
2315 cfg.cls += ' navbar-right';
2317 cfg.cls += ' navbar-left';
2321 if (this.align === 'right') {
2322 cfg.cls += ' navbar-right';
2326 cfg.cls += ' navbar-inverse';
2334 setActiveItem : function(item)
2337 Roo.each(this.navItems, function(v){
2339 v.setActive(false, true);
2346 item.setActive(true, true);
2347 this.fireEvent('changed', this, item, prev);
2353 register : function(item)
2355 this.navItems.push( item);
2356 item.navId = this.navId;
2359 getNavItem: function(tabId)
2362 Roo.each(this.navItems, function(e) {
2363 if (e.tabId == tabId) {
2375 Roo.apply(Roo.bootstrap.NavGroup, {
2379 register : function(navgrp)
2381 this.groups[navgrp.navId] = navgrp;
2384 get: function(navId) {
2385 return this.groups[navId];
2400 * @class Roo.bootstrap.Navbar.Item
2401 * @extends Roo.bootstrap.Component
2402 * Bootstrap Navbar.Button class
2403 * @cfg {String} href link to
2404 * @cfg {String} html content of button
2405 * @cfg {String} badge text inside badge
2406 * @cfg {String} glyphicon name of glyphicon
2407 * @cfg {String} icon name of font awesome icon
2408 * @cfg {Boolean} active Is item active
2409 * @cfg {Boolean} preventDefault (true | false) default false
2410 * @cfg {String} tabId the tab that this item activates.
2413 * Create a new Navbar Button
2414 * @param {Object} config The config object
2416 Roo.bootstrap.Navbar.Item = function(config){
2417 Roo.bootstrap.Navbar.Item.superclass.constructor.call(this, config);
2422 * The raw click event for the entire grid.
2423 * @param {Roo.EventObject} e
2428 * Fires when the active item active state changes
2429 * @param {Roo.bootstrap.Navbar.Item} this
2430 * @param {boolean} state the new state
2438 Roo.extend(Roo.bootstrap.Navbar.Item, Roo.bootstrap.Component, {
2446 preventDefault : false,
2449 getAutoCreate : function(){
2451 var cfg = Roo.apply({}, Roo.bootstrap.Navbar.Item.superclass.getAutoCreate.call(this));
2453 if (this.parent().parent().sidebar === true) {
2466 cfg.cn[0].html = this.html;
2470 this.cls += ' active';
2474 cfg.cn[0].cls += ' dropdown-toggle';
2475 cfg.cn[0].html = (cfg.cn[0].html || this.html) + '<span class="glyphicon glyphicon-chevron-down"></span>';
2479 cfg.cn[0].tag = 'a',
2480 cfg.cn[0].href = this.href;
2483 if (this.glyphicon) {
2484 cfg.cn[0].html = '<i class="glyphicon glyphicon-'+this.glyphicon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
2488 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
2500 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
2510 if (this.glyphicon) {
2511 if(cfg.html){cfg.html = ' ' + this.html};
2515 cls: 'glyphicon glyphicon-' + this.glyphicon
2520 cfg.cn[0].html = this.html || cfg.cn[0].html ;
2525 cfg.cn[0].html += " <span class='caret'></span>";
2526 //}else if (!this.href) {
2527 // cfg.cn[0].tag='p';
2528 // cfg.cn[0].cls='navbar-text';
2531 cfg.cn[0].href=this.href||'#';
2532 cfg.cn[0].html=this.html;
2535 if (this.badge !== '') {
2538 cfg.cn[0].html + ' ',
2549 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
2554 initEvents: function() {
2555 // Roo.log('init events?');
2556 // Roo.log(this.el.dom);
2557 this.el.select('a',true).on('click', this.onClick, this);
2558 // at this point parent should be available..
2559 this.parent().register(this);
2562 onClick : function(e)
2564 if(this.preventDefault){
2568 if(this.fireEvent('click', this, e) === false){
2572 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
2573 if (typeof(this.parent().setActiveItem) !== 'undefined') {
2574 this.parent().setActiveItem(this);
2582 isActive: function () {
2585 setActive : function(state, fire)
2587 this.active = state;
2589 this.el.removeClass('active');
2590 } else if (!this.el.hasClass('active')) {
2591 this.el.addClass('active');
2594 this.fireEvent('changed', this, state);
2599 // this should not be here...
2612 * @class Roo.bootstrap.Row
2613 * @extends Roo.bootstrap.Component
2614 * Bootstrap Row class (contains columns...)
2618 * @param {Object} config The config object
2621 Roo.bootstrap.Row = function(config){
2622 Roo.bootstrap.Row.superclass.constructor.call(this, config);
2625 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
2627 getAutoCreate : function(){
2646 * @class Roo.bootstrap.Element
2647 * @extends Roo.bootstrap.Component
2648 * Bootstrap Element class
2649 * @cfg {String} html contents of the element
2650 * @cfg {String} tag tag of the element
2651 * @cfg {String} cls class of the element
2654 * Create a new Element
2655 * @param {Object} config The config object
2658 Roo.bootstrap.Element = function(config){
2659 Roo.bootstrap.Element.superclass.constructor.call(this, config);
2662 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
2669 getAutoCreate : function(){
2694 * @class Roo.bootstrap.Pagination
2695 * @extends Roo.bootstrap.Component
2696 * Bootstrap Pagination class
2697 * @cfg {String} size xs | sm | md | lg
2698 * @cfg {Boolean} inverse false | true
2701 * Create a new Pagination
2702 * @param {Object} config The config object
2705 Roo.bootstrap.Pagination = function(config){
2706 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
2709 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
2715 getAutoCreate : function(){
2721 cfg.cls += ' inverse';
2727 cfg.cls += " " + this.cls;
2745 * @class Roo.bootstrap.PaginationItem
2746 * @extends Roo.bootstrap.Component
2747 * Bootstrap PaginationItem class
2748 * @cfg {String} html text
2749 * @cfg {String} href the link
2750 * @cfg {Boolean} preventDefault (true | false) default true
2751 * @cfg {Boolean} active (true | false) default false
2755 * Create a new PaginationItem
2756 * @param {Object} config The config object
2760 Roo.bootstrap.PaginationItem = function(config){
2761 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
2766 * The raw click event for the entire grid.
2767 * @param {Roo.EventObject} e
2773 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
2777 preventDefault: true,
2781 getAutoCreate : function(){
2787 href : this.href ? this.href : '#',
2788 html : this.html ? this.html : ''
2798 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
2804 initEvents: function() {
2806 this.el.on('click', this.onClick, this);
2809 onClick : function(e)
2811 Roo.log('PaginationItem on click ');
2812 if(this.preventDefault){
2816 this.fireEvent('click', this, e);
2832 * @class Roo.bootstrap.Slider
2833 * @extends Roo.bootstrap.Component
2834 * Bootstrap Slider class
2837 * Create a new Slider
2838 * @param {Object} config The config object
2841 Roo.bootstrap.Slider = function(config){
2842 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
2845 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
2847 getAutoCreate : function(){
2851 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
2855 cls: 'ui-slider-handle ui-state-default ui-corner-all'
2873 * @class Roo.bootstrap.Table
2874 * @extends Roo.bootstrap.Component
2875 * Bootstrap Table class
2876 * @cfg {String} cls table class
2877 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
2878 * @cfg {String} bgcolor Specifies the background color for a table
2879 * @cfg {Number} border Specifies whether the table cells should have borders or not
2880 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
2881 * @cfg {Number} cellspacing Specifies the space between cells
2882 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
2883 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
2884 * @cfg {String} sortable Specifies that the table should be sortable
2885 * @cfg {String} summary Specifies a summary of the content of a table
2886 * @cfg {Number} width Specifies the width of a table
2888 * @cfg {boolean} striped Should the rows be alternative striped
2889 * @cfg {boolean} bordered Add borders to the table
2890 * @cfg {boolean} hover Add hover highlighting
2891 * @cfg {boolean} condensed Format condensed
2892 * @cfg {boolean} responsive Format condensed
2898 * Create a new Table
2899 * @param {Object} config The config object
2902 Roo.bootstrap.Table = function(config){
2903 Roo.bootstrap.Table.superclass.constructor.call(this, config);
2906 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
2907 this.sm = this.selModel;
2908 this.sm.xmodule = this.xmodule || false;
2910 if (this.cm && typeof(this.cm.config) == 'undefined') {
2911 this.colModel = new Roo.bootstrap.Table.ColumnModel(this.cm);
2912 this.cm = this.colModel;
2913 this.cm.xmodule = this.xmodule || false;
2916 this.store= Roo.factory(this.store, Roo.data);
2917 this.ds = this.store;
2918 this.ds.xmodule = this.xmodule || false;
2923 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
2945 getAutoCreate : function(){
2946 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
2955 cfg.cls += ' table-striped';
2958 cfg.cls += ' table-hover';
2960 if (this.bordered) {
2961 cfg.cls += ' table-bordered';
2963 if (this.condensed) {
2964 cfg.cls += ' table-condensed';
2966 if (this.responsive) {
2967 cfg.cls += ' table-responsive';
2974 cfg.cls+= ' ' +this.cls;
2977 // this lot should be simplifed...
2980 cfg.align=this.align;
2983 cfg.bgcolor=this.bgcolor;
2986 cfg.border=this.border;
2988 if (this.cellpadding) {
2989 cfg.cellpadding=this.cellpadding;
2991 if (this.cellspacing) {
2992 cfg.cellspacing=this.cellspacing;
2995 cfg.frame=this.frame;
2998 cfg.rules=this.rules;
3000 if (this.sortable) {
3001 cfg.sortable=this.sortable;
3004 cfg.summary=this.summary;
3007 cfg.width=this.width;
3010 if(this.store || this.cm){
3011 cfg.cn.push(this.renderHeader());
3012 cfg.cn.push(this.renderBody());
3013 cfg.cn.push(this.renderFooter());
3015 cfg.cls+= ' TableGrid';
3021 // initTableGrid : function()
3030 // var cm = this.cm;
3032 // for(var i = 0, len = cm.getColumnCount(); i < len; i++){
3035 // html: cm.getColumnHeader(i)
3039 // cfg.push(header);
3046 initEvents : function()
3048 if(!this.store || !this.cm){
3052 Roo.log('initEvents with ds!!!!');
3056 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
3057 e.on('click', _this.sort, _this);
3059 // this.maskEl = Roo.DomHelper.append(this.el.select('.TableGrid', true).first(), {tag: "div", cls:"x-dlg-mask"}, true);
3060 // this.maskEl.enableDisplayMode("block");
3061 // this.maskEl.show();
3063 this.store.on('load', this.onLoad, this);
3064 this.store.on('beforeload', this.onBeforeLoad, this);
3072 sort : function(e,el)
3074 var col = Roo.get(el)
3076 if(!col.hasClass('sortable')){
3080 var sort = col.attr('sort');
3083 if(col.hasClass('glyphicon-arrow-up')){
3087 this.store.sortInfo = {field : sort, direction : dir};
3092 renderHeader : function()
3101 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
3103 var config = cm.config[i];
3107 html: cm.getColumnHeader(i)
3110 if(typeof(config.dataIndex) != 'undefined'){
3111 c.sort = config.dataIndex;
3114 if(typeof(config.sortable) != 'undefined' && config.sortable){
3118 if(typeof(config.width) != 'undefined'){
3119 c.style = 'width:' + config.width + 'px';
3128 renderBody : function()
3138 renderFooter : function()
3150 Roo.log('ds onload');
3155 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
3156 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
3158 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
3159 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
3162 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
3163 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
3167 var tbody = this.el.select('tbody', true).first();
3171 if(this.store.getCount() > 0){
3172 this.store.data.each(function(d){
3178 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
3179 var renderer = cm.getRenderer(i);
3180 var config = cm.config[i];
3184 if(typeof(renderer) !== 'undefined'){
3185 value = renderer(d.data[cm.getDataIndex(i)], false, d);
3188 if(typeof(value) === 'object'){
3198 html: (typeof(value) === 'object') ? '' : value
3201 if(typeof(config.width) != 'undefined'){
3202 td.style = 'width:' + config.width + 'px';
3209 tbody.createChild(row);
3217 Roo.each(renders, function(r){
3218 _this.renderColumn(r);
3222 // if(this.loadMask){
3223 // this.maskEl.hide();
3227 onBeforeLoad : function()
3229 Roo.log('ds onBeforeLoad');
3233 // if(this.loadMask){
3234 // this.maskEl.show();
3240 this.el.select('tbody', true).first().dom.innerHTML = '';
3243 getSelectionModel : function(){
3245 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
3247 return this.selModel;
3250 renderColumn : function(r)
3253 r.cfg.render(Roo.get(r.id));
3256 Roo.each(r.cfg.cn, function(c){
3261 _this.renderColumn(child);
3278 * @class Roo.bootstrap.TableCell
3279 * @extends Roo.bootstrap.Component
3280 * Bootstrap TableCell class
3281 * @cfg {String} html cell contain text
3282 * @cfg {String} cls cell class
3283 * @cfg {String} tag cell tag (td|th) default td
3284 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
3285 * @cfg {String} align Aligns the content in a cell
3286 * @cfg {String} axis Categorizes cells
3287 * @cfg {String} bgcolor Specifies the background color of a cell
3288 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
3289 * @cfg {Number} colspan Specifies the number of columns a cell should span
3290 * @cfg {String} headers Specifies one or more header cells a cell is related to
3291 * @cfg {Number} height Sets the height of a cell
3292 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
3293 * @cfg {Number} rowspan Sets the number of rows a cell should span
3294 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
3295 * @cfg {String} valign Vertical aligns the content in a cell
3296 * @cfg {Number} width Specifies the width of a cell
3299 * Create a new TableCell
3300 * @param {Object} config The config object
3303 Roo.bootstrap.TableCell = function(config){
3304 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
3307 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
3327 getAutoCreate : function(){
3328 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
3348 cfg.align=this.align
3354 cfg.bgcolor=this.bgcolor
3357 cfg.charoff=this.charoff
3360 cfg.colspan=this.colspan
3363 cfg.headers=this.headers
3366 cfg.height=this.height
3369 cfg.nowrap=this.nowrap
3372 cfg.rowspan=this.rowspan
3375 cfg.scope=this.scope
3378 cfg.valign=this.valign
3381 cfg.width=this.width
3400 * @class Roo.bootstrap.TableRow
3401 * @extends Roo.bootstrap.Component
3402 * Bootstrap TableRow class
3403 * @cfg {String} cls row class
3404 * @cfg {String} align Aligns the content in a table row
3405 * @cfg {String} bgcolor Specifies a background color for a table row
3406 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
3407 * @cfg {String} valign Vertical aligns the content in a table row
3410 * Create a new TableRow
3411 * @param {Object} config The config object
3414 Roo.bootstrap.TableRow = function(config){
3415 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
3418 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
3426 getAutoCreate : function(){
3427 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
3437 cfg.align = this.align;
3440 cfg.bgcolor = this.bgcolor;
3443 cfg.charoff = this.charoff;
3446 cfg.valign = this.valign;
3464 * @class Roo.bootstrap.TableBody
3465 * @extends Roo.bootstrap.Component
3466 * Bootstrap TableBody class
3467 * @cfg {String} cls element class
3468 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
3469 * @cfg {String} align Aligns the content inside the element
3470 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
3471 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
3474 * Create a new TableBody
3475 * @param {Object} config The config object
3478 Roo.bootstrap.TableBody = function(config){
3479 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
3482 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
3490 getAutoCreate : function(){
3491 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
3505 cfg.align = this.align;
3508 cfg.charoff = this.charoff;
3511 cfg.valign = this.valign;
3518 // initEvents : function()
3525 // this.store = Roo.factory(this.store, Roo.data);
3526 // this.store.on('load', this.onLoad, this);
3528 // this.store.load();
3532 // onLoad: function ()
3534 // this.fireEvent('load', this);
3544 * Ext JS Library 1.1.1
3545 * Copyright(c) 2006-2007, Ext JS, LLC.
3547 * Originally Released Under LGPL - original licence link has changed is not relivant.
3550 * <script type="text/javascript">
3553 // as we use this in bootstrap.
3554 Roo.namespace('Roo.form');
3556 * @class Roo.form.Action
3557 * Internal Class used to handle form actions
3559 * @param {Roo.form.BasicForm} el The form element or its id
3560 * @param {Object} config Configuration options
3565 // define the action interface
3566 Roo.form.Action = function(form, options){
3568 this.options = options || {};
3571 * Client Validation Failed
3574 Roo.form.Action.CLIENT_INVALID = 'client';
3576 * Server Validation Failed
3579 Roo.form.Action.SERVER_INVALID = 'server';
3581 * Connect to Server Failed
3584 Roo.form.Action.CONNECT_FAILURE = 'connect';
3586 * Reading Data from Server Failed
3589 Roo.form.Action.LOAD_FAILURE = 'load';
3591 Roo.form.Action.prototype = {
3593 failureType : undefined,
3594 response : undefined,
3598 run : function(options){
3603 success : function(response){
3608 handleResponse : function(response){
3612 // default connection failure
3613 failure : function(response){
3615 this.response = response;
3616 this.failureType = Roo.form.Action.CONNECT_FAILURE;
3617 this.form.afterAction(this, false);
3620 processResponse : function(response){
3621 this.response = response;
3622 if(!response.responseText){
3625 this.result = this.handleResponse(response);
3629 // utility functions used internally
3630 getUrl : function(appendParams){
3631 var url = this.options.url || this.form.url || this.form.el.dom.action;
3633 var p = this.getParams();
3635 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
3641 getMethod : function(){
3642 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
3645 getParams : function(){
3646 var bp = this.form.baseParams;
3647 var p = this.options.params;
3649 if(typeof p == "object"){
3650 p = Roo.urlEncode(Roo.applyIf(p, bp));
3651 }else if(typeof p == 'string' && bp){
3652 p += '&' + Roo.urlEncode(bp);
3655 p = Roo.urlEncode(bp);
3660 createCallback : function(){
3662 success: this.success,
3663 failure: this.failure,
3665 timeout: (this.form.timeout*1000),
3666 upload: this.form.fileUpload ? this.success : undefined
3671 Roo.form.Action.Submit = function(form, options){
3672 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
3675 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
3678 haveProgress : false,
3679 uploadComplete : false,
3681 // uploadProgress indicator.
3682 uploadProgress : function()
3684 if (!this.form.progressUrl) {
3688 if (!this.haveProgress) {
3689 Roo.MessageBox.progress("Uploading", "Uploading");
3691 if (this.uploadComplete) {
3692 Roo.MessageBox.hide();
3696 this.haveProgress = true;
3698 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
3700 var c = new Roo.data.Connection();
3702 url : this.form.progressUrl,
3707 success : function(req){
3708 //console.log(data);
3712 rdata = Roo.decode(req.responseText)
3714 Roo.log("Invalid data from server..");
3718 if (!rdata || !rdata.success) {
3720 Roo.MessageBox.alert(Roo.encode(rdata));
3723 var data = rdata.data;
3725 if (this.uploadComplete) {
3726 Roo.MessageBox.hide();
3731 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
3732 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
3735 this.uploadProgress.defer(2000,this);
3738 failure: function(data) {
3739 Roo.log('progress url failed ');
3750 // run get Values on the form, so it syncs any secondary forms.
3751 this.form.getValues();
3753 var o = this.options;
3754 var method = this.getMethod();
3755 var isPost = method == 'POST';
3756 if(o.clientValidation === false || this.form.isValid()){
3758 if (this.form.progressUrl) {
3759 this.form.findField('UPLOAD_IDENTIFIER').setValue(
3760 (new Date() * 1) + '' + Math.random());
3765 Roo.Ajax.request(Roo.apply(this.createCallback(), {
3766 form:this.form.el.dom,
3767 url:this.getUrl(!isPost),
3769 params:isPost ? this.getParams() : null,
3770 isUpload: this.form.fileUpload
3773 this.uploadProgress();
3775 }else if (o.clientValidation !== false){ // client validation failed
3776 this.failureType = Roo.form.Action.CLIENT_INVALID;
3777 this.form.afterAction(this, false);
3781 success : function(response)
3783 this.uploadComplete= true;
3784 if (this.haveProgress) {
3785 Roo.MessageBox.hide();
3789 var result = this.processResponse(response);
3790 if(result === true || result.success){
3791 this.form.afterAction(this, true);
3795 this.form.markInvalid(result.errors);
3796 this.failureType = Roo.form.Action.SERVER_INVALID;
3798 this.form.afterAction(this, false);
3800 failure : function(response)
3802 this.uploadComplete= true;
3803 if (this.haveProgress) {
3804 Roo.MessageBox.hide();
3807 this.response = response;
3808 this.failureType = Roo.form.Action.CONNECT_FAILURE;
3809 this.form.afterAction(this, false);
3812 handleResponse : function(response){
3813 if(this.form.errorReader){
3814 var rs = this.form.errorReader.read(response);
3817 for(var i = 0, len = rs.records.length; i < len; i++) {
3818 var r = rs.records[i];
3822 if(errors.length < 1){
3826 success : rs.success,
3832 ret = Roo.decode(response.responseText);
3836 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
3846 Roo.form.Action.Load = function(form, options){
3847 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
3848 this.reader = this.form.reader;
3851 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
3856 Roo.Ajax.request(Roo.apply(
3857 this.createCallback(), {
3858 method:this.getMethod(),
3859 url:this.getUrl(false),
3860 params:this.getParams()
3864 success : function(response){
3866 var result = this.processResponse(response);
3867 if(result === true || !result.success || !result.data){
3868 this.failureType = Roo.form.Action.LOAD_FAILURE;
3869 this.form.afterAction(this, false);
3872 this.form.clearInvalid();
3873 this.form.setValues(result.data);
3874 this.form.afterAction(this, true);
3877 handleResponse : function(response){
3878 if(this.form.reader){
3879 var rs = this.form.reader.read(response);
3880 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
3882 success : rs.success,
3886 return Roo.decode(response.responseText);
3890 Roo.form.Action.ACTION_TYPES = {
3891 'load' : Roo.form.Action.Load,
3892 'submit' : Roo.form.Action.Submit
3901 * @class Roo.bootstrap.Form
3902 * @extends Roo.bootstrap.Component
3903 * Bootstrap Form class
3904 * @cfg {String} method GET | POST (default POST)
3905 * @cfg {String} labelAlign top | left (default top)
3906 * @cfg {String} align left | right - for navbars
3911 * @param {Object} config The config object
3915 Roo.bootstrap.Form = function(config){
3916 Roo.bootstrap.Form.superclass.constructor.call(this, config);
3919 * @event clientvalidation
3920 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
3921 * @param {Form} this
3922 * @param {Boolean} valid true if the form has passed client-side validation
3924 clientvalidation: true,
3926 * @event beforeaction
3927 * Fires before any action is performed. Return false to cancel the action.
3928 * @param {Form} this
3929 * @param {Action} action The action to be performed
3933 * @event actionfailed
3934 * Fires when an action fails.
3935 * @param {Form} this
3936 * @param {Action} action The action that failed
3938 actionfailed : true,
3940 * @event actioncomplete
3941 * Fires when an action is completed.
3942 * @param {Form} this
3943 * @param {Action} action The action that completed
3945 actioncomplete : true
3950 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
3953 * @cfg {String} method
3954 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
3959 * The URL to use for form actions if one isn't supplied in the action options.
3962 * @cfg {Boolean} fileUpload
3963 * Set to true if this form is a file upload.
3967 * @cfg {Object} baseParams
3968 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
3972 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
3976 * @cfg {Sting} align (left|right) for navbar forms
3981 activeAction : null,
3984 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
3985 * element by passing it or its id or mask the form itself by passing in true.
3988 waitMsgTarget : false,
3993 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
3994 * element by passing it or its id or mask the form itself by passing in true.
3998 getAutoCreate : function(){
4002 method : this.method || 'POST',
4003 id : this.id || Roo.id(),
4006 if (this.parent().xtype.match(/^Nav/)) {
4007 cfg.cls = 'navbar-form navbar-' + this.align;
4011 if (this.labelAlign == 'left' ) {
4012 cfg.cls += ' form-horizontal';
4018 initEvents : function()
4020 this.el.on('submit', this.onSubmit, this);
4025 onSubmit : function(e){
4030 * Returns true if client-side validation on the form is successful.
4033 isValid : function(){
4034 var items = this.getItems();
4036 items.each(function(f){
4045 * Returns true if any fields in this form have changed since their original load.
4048 isDirty : function(){
4050 var items = this.getItems();
4051 items.each(function(f){
4061 * Performs a predefined action (submit or load) or custom actions you define on this form.
4062 * @param {String} actionName The name of the action type
4063 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
4064 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
4065 * accept other config options):
4067 Property Type Description
4068 ---------------- --------------- ----------------------------------------------------------------------------------
4069 url String The url for the action (defaults to the form's url)
4070 method String The form method to use (defaults to the form's method, or POST if not defined)
4071 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
4072 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
4073 validate the form on the client (defaults to false)
4075 * @return {BasicForm} this
4077 doAction : function(action, options){
4078 if(typeof action == 'string'){
4079 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
4081 if(this.fireEvent('beforeaction', this, action) !== false){
4082 this.beforeAction(action);
4083 action.run.defer(100, action);
4089 beforeAction : function(action){
4090 var o = action.options;
4092 // not really supported yet.. ??
4094 //if(this.waitMsgTarget === true){
4095 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
4096 //}else if(this.waitMsgTarget){
4097 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
4098 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
4100 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
4106 afterAction : function(action, success){
4107 this.activeAction = null;
4108 var o = action.options;
4110 //if(this.waitMsgTarget === true){
4112 //}else if(this.waitMsgTarget){
4113 // this.waitMsgTarget.unmask();
4115 // Roo.MessageBox.updateProgress(1);
4116 // Roo.MessageBox.hide();
4123 Roo.callback(o.success, o.scope, [this, action]);
4124 this.fireEvent('actioncomplete', this, action);
4128 // failure condition..
4129 // we have a scenario where updates need confirming.
4130 // eg. if a locking scenario exists..
4131 // we look for { errors : { needs_confirm : true }} in the response.
4133 (typeof(action.result) != 'undefined') &&
4134 (typeof(action.result.errors) != 'undefined') &&
4135 (typeof(action.result.errors.needs_confirm) != 'undefined')
4138 Roo.log("not supported yet");
4141 Roo.MessageBox.confirm(
4142 "Change requires confirmation",
4143 action.result.errorMsg,
4148 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
4158 Roo.callback(o.failure, o.scope, [this, action]);
4159 // show an error message if no failed handler is set..
4160 if (!this.hasListener('actionfailed')) {
4161 Roo.log("need to add dialog support");
4163 Roo.MessageBox.alert("Error",
4164 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
4165 action.result.errorMsg :
4166 "Saving Failed, please check your entries or try again"
4171 this.fireEvent('actionfailed', this, action);
4176 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
4177 * @param {String} id The value to search for
4180 findField : function(id){
4181 var items = this.getItems();
4182 var field = items.get(id);
4184 items.each(function(f){
4185 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
4192 return field || null;
4195 * Mark fields in this form invalid in bulk.
4196 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
4197 * @return {BasicForm} this
4199 markInvalid : function(errors){
4200 if(errors instanceof Array){
4201 for(var i = 0, len = errors.length; i < len; i++){
4202 var fieldError = errors[i];
4203 var f = this.findField(fieldError.id);
4205 f.markInvalid(fieldError.msg);
4211 if(typeof errors[id] != 'function' && (field = this.findField(id))){
4212 field.markInvalid(errors[id]);
4216 //Roo.each(this.childForms || [], function (f) {
4217 // f.markInvalid(errors);
4224 * Set values for fields in this form in bulk.
4225 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
4226 * @return {BasicForm} this
4228 setValues : function(values){
4229 if(values instanceof Array){ // array of objects
4230 for(var i = 0, len = values.length; i < len; i++){
4232 var f = this.findField(v.id);
4234 f.setValue(v.value);
4235 if(this.trackResetOnLoad){
4236 f.originalValue = f.getValue();
4240 }else{ // object hash
4243 if(typeof values[id] != 'function' && (field = this.findField(id))){
4245 if (field.setFromData &&
4247 field.displayField &&
4248 // combos' with local stores can
4249 // be queried via setValue()
4250 // to set their value..
4251 (field.store && !field.store.isLocal)
4255 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
4256 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
4257 field.setFromData(sd);
4260 field.setValue(values[id]);
4264 if(this.trackResetOnLoad){
4265 field.originalValue = field.getValue();
4271 //Roo.each(this.childForms || [], function (f) {
4272 // f.setValues(values);
4279 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
4280 * they are returned as an array.
4281 * @param {Boolean} asString
4284 getValues : function(asString){
4285 //if (this.childForms) {
4286 // copy values from the child forms
4287 // Roo.each(this.childForms, function (f) {
4288 // this.setValues(f.getValues());
4294 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
4295 if(asString === true){
4298 return Roo.urlDecode(fs);
4302 * Returns the fields in this form as an object with key/value pairs.
4303 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
4306 getFieldValues : function(with_hidden)
4308 var items = this.getItems();
4310 items.each(function(f){
4314 var v = f.getValue();
4315 if (f.inputType =='radio') {
4316 if (typeof(ret[f.getName()]) == 'undefined') {
4317 ret[f.getName()] = ''; // empty..
4320 if (!f.el.dom.checked) {
4328 // not sure if this supported any more..
4329 if ((typeof(v) == 'object') && f.getRawValue) {
4330 v = f.getRawValue() ; // dates..
4332 // combo boxes where name != hiddenName...
4333 if (f.name != f.getName()) {
4334 ret[f.name] = f.getRawValue();
4336 ret[f.getName()] = v;
4343 * Clears all invalid messages in this form.
4344 * @return {BasicForm} this
4346 clearInvalid : function(){
4347 var items = this.getItems();
4349 items.each(function(f){
4360 * @return {BasicForm} this
4363 var items = this.getItems();
4364 items.each(function(f){
4368 Roo.each(this.childForms || [], function (f) {
4375 getItems : function()
4377 var r=new Roo.util.MixedCollection(false, function(o){
4378 return o.id || (o.id = Roo.id());
4380 var iter = function(el) {
4387 Roo.each(el.items,function(e) {
4406 * Ext JS Library 1.1.1
4407 * Copyright(c) 2006-2007, Ext JS, LLC.
4409 * Originally Released Under LGPL - original licence link has changed is not relivant.
4412 * <script type="text/javascript">
4415 * @class Roo.form.VTypes
4416 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
4419 Roo.form.VTypes = function(){
4420 // closure these in so they are only created once.
4421 var alpha = /^[a-zA-Z_]+$/;
4422 var alphanum = /^[a-zA-Z0-9_]+$/;
4423 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
4424 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
4426 // All these messages and functions are configurable
4429 * The function used to validate email addresses
4430 * @param {String} value The email address
4432 'email' : function(v){
4433 return email.test(v);
4436 * The error text to display when the email validation function returns false
4439 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
4441 * The keystroke filter mask to be applied on email input
4444 'emailMask' : /[a-z0-9_\.\-@]/i,
4447 * The function used to validate URLs
4448 * @param {String} value The URL
4450 'url' : function(v){
4454 * The error text to display when the url validation function returns false
4457 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
4460 * The function used to validate alpha values
4461 * @param {String} value The value
4463 'alpha' : function(v){
4464 return alpha.test(v);
4467 * The error text to display when the alpha validation function returns false
4470 'alphaText' : 'This field should only contain letters and _',
4472 * The keystroke filter mask to be applied on alpha input
4475 'alphaMask' : /[a-z_]/i,
4478 * The function used to validate alphanumeric values
4479 * @param {String} value The value
4481 'alphanum' : function(v){
4482 return alphanum.test(v);
4485 * The error text to display when the alphanumeric validation function returns false
4488 'alphanumText' : 'This field should only contain letters, numbers and _',
4490 * The keystroke filter mask to be applied on alphanumeric input
4493 'alphanumMask' : /[a-z0-9_]/i
4503 * @class Roo.bootstrap.Input
4504 * @extends Roo.bootstrap.Component
4505 * Bootstrap Input class
4506 * @cfg {Boolean} disabled is it disabled
4507 * @cfg {String} fieldLabel - the label associated
4508 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
4509 * @cfg {String} name name of the input
4510 * @cfg {string} fieldLabel - the label associated
4511 * @cfg {string} inputType - input / file submit ...
4512 * @cfg {string} placeholder - placeholder to put in text.
4513 * @cfg {string} before - input group add on before
4514 * @cfg {string} after - input group add on after
4515 * @cfg {string} size - (lg|sm) or leave empty..
4516 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
4517 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
4518 * @cfg {Number} md colspan out of 12 for computer-sized screens
4519 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
4520 * @cfg {string} value default value of the input
4521 * @cfg {Number} labelWidth set the width of label (0-12)
4522 * @cfg {String} labelAlign (top|left)
4523 * @cfg {Boolean} readOnly Specifies that the field should be read-only
4527 * Create a new Input
4528 * @param {Object} config The config object
4531 Roo.bootstrap.Input = function(config){
4532 Roo.bootstrap.Input.superclass.constructor.call(this, config);
4537 * Fires when this field receives input focus.
4538 * @param {Roo.form.Field} this
4543 * Fires when this field loses input focus.
4544 * @param {Roo.form.Field} this
4549 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
4550 * {@link Roo.EventObject#getKey} to determine which key was pressed.
4551 * @param {Roo.form.Field} this
4552 * @param {Roo.EventObject} e The event object
4557 * Fires just before the field blurs if the field value has changed.
4558 * @param {Roo.form.Field} this
4559 * @param {Mixed} newValue The new value
4560 * @param {Mixed} oldValue The original value
4565 * Fires after the field has been marked as invalid.
4566 * @param {Roo.form.Field} this
4567 * @param {String} msg The validation message
4572 * Fires after the field has been validated with no errors.
4573 * @param {Roo.form.Field} this
4578 * Fires after the key up
4579 * @param {Roo.form.Field} this
4580 * @param {Roo.EventObject} e The event Object
4586 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
4588 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
4589 automatic validation (defaults to "keyup").
4591 validationEvent : "keyup",
4593 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
4595 validateOnBlur : true,
4597 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
4599 validationDelay : 250,
4601 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
4603 focusClass : "x-form-focus", // not needed???
4607 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
4609 invalidClass : "has-error",
4612 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
4614 selectOnFocus : false,
4617 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
4621 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
4626 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
4628 disableKeyFilter : false,
4631 * @cfg {Boolean} disabled True to disable the field (defaults to false).
4635 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
4639 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
4641 blankText : "This field is required",
4644 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
4648 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
4650 maxLength : Number.MAX_VALUE,
4652 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
4654 minLengthText : "The minimum length for this field is {0}",
4656 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
4658 maxLengthText : "The maximum length for this field is {0}",
4662 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
4663 * If available, this function will be called only after the basic validators all return true, and will be passed the
4664 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
4668 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
4669 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
4670 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
4674 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
4697 parentLabelAlign : function()
4700 while (parent.parent()) {
4701 parent = parent.parent();
4702 if (typeof(parent.labelAlign) !='undefined') {
4703 return parent.labelAlign;
4710 getAutoCreate : function(){
4712 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
4718 if(this.inputType != 'hidden'){
4719 cfg.cls = 'form-group' //input-group
4725 type : this.inputType,
4727 cls : 'form-control',
4728 placeholder : this.placeholder || ''
4732 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
4733 input.maxLength = this.maxLength;
4736 if (this.disabled) {
4737 input.disabled=true;
4740 if (this.readOnly) {
4741 input.readonly=true;
4745 input.name = this.name;
4748 input.cls += ' input-' + this.size;
4751 ['xs','sm','md','lg'].map(function(size){
4752 if (settings[size]) {
4753 cfg.cls += ' col-' + size + '-' + settings[size];
4757 var inputblock = input;
4759 if (this.before || this.after) {
4762 cls : 'input-group',
4766 inputblock.cn.push({
4768 cls : 'input-group-addon',
4772 inputblock.cn.push(input);
4774 inputblock.cn.push({
4776 cls : 'input-group-addon',
4783 if (align ==='left' && this.fieldLabel.length) {
4784 Roo.log("left and has label");
4790 cls : 'control-label col-sm-' + this.labelWidth,
4791 html : this.fieldLabel
4795 cls : "col-sm-" + (12 - this.labelWidth),
4802 } else if ( this.fieldLabel.length) {
4808 //cls : 'input-group-addon',
4809 html : this.fieldLabel
4819 Roo.log(" no label && no align");
4828 Roo.log('input-parentType: ' + this.parentType);
4830 if (this.parentType === 'Navbar' && this.parent().bar) {
4831 cfg.cls += ' navbar-form';
4839 * return the real input element.
4841 inputEl: function ()
4843 return this.el.select('input.form-control',true).first();
4845 setDisabled : function(v)
4847 var i = this.inputEl().dom;
4849 i.removeAttribute('disabled');
4853 i.setAttribute('disabled','true');
4855 initEvents : function()
4858 this.inputEl().on("keydown" , this.fireKey, this);
4859 this.inputEl().on("focus", this.onFocus, this);
4860 this.inputEl().on("blur", this.onBlur, this);
4862 this.inputEl().relayEvent('keyup', this);
4864 // reference to original value for reset
4865 this.originalValue = this.getValue();
4866 //Roo.form.TextField.superclass.initEvents.call(this);
4867 if(this.validationEvent == 'keyup'){
4868 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
4869 this.inputEl().on('keyup', this.filterValidation, this);
4871 else if(this.validationEvent !== false){
4872 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
4875 if(this.selectOnFocus){
4876 this.on("focus", this.preFocus, this);
4879 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
4880 this.inputEl().on("keypress", this.filterKeys, this);
4883 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
4884 this.el.on("click", this.autoSize, this);
4887 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
4888 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
4892 filterValidation : function(e){
4893 if(!e.isNavKeyPress()){
4894 this.validationTask.delay(this.validationDelay);
4898 * Validates the field value
4899 * @return {Boolean} True if the value is valid, else false
4901 validate : function(){
4902 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
4903 if(this.disabled || this.validateValue(this.getRawValue())){
4904 this.clearInvalid();
4912 * Validates a value according to the field's validation rules and marks the field as invalid
4913 * if the validation fails
4914 * @param {Mixed} value The value to validate
4915 * @return {Boolean} True if the value is valid, else false
4917 validateValue : function(value){
4918 if(value.length < 1) { // if it's blank
4919 if(this.allowBlank){
4920 this.clearInvalid();
4923 this.markInvalid(this.blankText);
4927 if(value.length < this.minLength){
4928 this.markInvalid(String.format(this.minLengthText, this.minLength));
4931 if(value.length > this.maxLength){
4932 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
4936 var vt = Roo.form.VTypes;
4937 if(!vt[this.vtype](value, this)){
4938 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
4942 if(typeof this.validator == "function"){
4943 var msg = this.validator(value);
4945 this.markInvalid(msg);
4949 if(this.regex && !this.regex.test(value)){
4950 this.markInvalid(this.regexText);
4959 fireKey : function(e){
4960 //Roo.log('field ' + e.getKey());
4961 if(e.isNavKeyPress()){
4962 this.fireEvent("specialkey", this, e);
4965 focus : function (selectText){
4967 this.inputEl().focus();
4968 if(selectText === true){
4969 this.inputEl().dom.select();
4975 onFocus : function(){
4976 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
4977 // this.el.addClass(this.focusClass);
4980 this.hasFocus = true;
4981 this.startValue = this.getValue();
4982 this.fireEvent("focus", this);
4986 beforeBlur : Roo.emptyFn,
4990 onBlur : function(){
4992 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
4993 //this.el.removeClass(this.focusClass);
4995 this.hasFocus = false;
4996 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
4999 var v = this.getValue();
5000 if(String(v) !== String(this.startValue)){
5001 this.fireEvent('change', this, v, this.startValue);
5003 this.fireEvent("blur", this);
5007 * Resets the current field value to the originally loaded value and clears any validation messages
5010 this.setValue(this.originalValue);
5011 this.clearInvalid();
5014 * Returns the name of the field
5015 * @return {Mixed} name The name field
5017 getName: function(){
5021 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
5022 * @return {Mixed} value The field value
5024 getValue : function(){
5025 return this.inputEl().getValue();
5028 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
5029 * @return {Mixed} value The field value
5031 getRawValue : function(){
5032 var v = this.inputEl().getValue();
5038 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
5039 * @param {Mixed} value The value to set
5041 setRawValue : function(v){
5042 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
5045 selectText : function(start, end){
5046 var v = this.getRawValue();
5048 start = start === undefined ? 0 : start;
5049 end = end === undefined ? v.length : end;
5050 var d = this.inputEl().dom;
5051 if(d.setSelectionRange){
5052 d.setSelectionRange(start, end);
5053 }else if(d.createTextRange){
5054 var range = d.createTextRange();
5055 range.moveStart("character", start);
5056 range.moveEnd("character", v.length-end);
5063 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
5064 * @param {Mixed} value The value to set
5066 setValue : function(v){
5069 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
5075 processValue : function(value){
5076 if(this.stripCharsRe){
5077 var newValue = value.replace(this.stripCharsRe, '');
5078 if(newValue !== value){
5079 this.setRawValue(newValue);
5086 preFocus : function(){
5088 if(this.selectOnFocus){
5089 this.inputEl().dom.select();
5092 filterKeys : function(e){
5094 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
5097 var c = e.getCharCode(), cc = String.fromCharCode(c);
5098 if(Roo.isIE && (e.isSpecialKey() || !cc)){
5101 if(!this.maskRe.test(cc)){
5106 * Clear any invalid styles/messages for this field
5108 clearInvalid : function(){
5110 if(!this.el || this.preventMark){ // not rendered
5113 this.el.removeClass(this.invalidClass);
5115 switch(this.msgTarget){
5117 this.el.dom.qtip = '';
5120 this.el.dom.title = '';
5124 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
5129 this.errorIcon.dom.qtip = '';
5130 this.errorIcon.hide();
5131 this.un('resize', this.alignErrorIcon, this);
5135 var t = Roo.getDom(this.msgTarget);
5137 t.style.display = 'none';
5141 this.fireEvent('valid', this);
5144 * Mark this field as invalid
5145 * @param {String} msg The validation message
5147 markInvalid : function(msg){
5148 if(!this.el || this.preventMark){ // not rendered
5151 this.el.addClass(this.invalidClass);
5153 msg = msg || this.invalidText;
5154 switch(this.msgTarget){
5156 this.el.dom.qtip = msg;
5157 this.el.dom.qclass = 'x-form-invalid-tip';
5158 if(Roo.QuickTips){ // fix for floating editors interacting with DND
5159 Roo.QuickTips.enable();
5163 this.el.dom.title = msg;
5167 var elp = this.el.findParent('.x-form-element', 5, true);
5168 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
5169 this.errorEl.setWidth(elp.getWidth(true)-20);
5171 this.errorEl.update(msg);
5172 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
5175 if(!this.errorIcon){
5176 var elp = this.el.findParent('.x-form-element', 5, true);
5177 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
5179 this.alignErrorIcon();
5180 this.errorIcon.dom.qtip = msg;
5181 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
5182 this.errorIcon.show();
5183 this.on('resize', this.alignErrorIcon, this);
5186 var t = Roo.getDom(this.msgTarget);
5188 t.style.display = this.msgDisplay;
5192 this.fireEvent('invalid', this, msg);
5195 SafariOnKeyDown : function(event)
5197 // this is a workaround for a password hang bug on chrome/ webkit.
5199 var isSelectAll = false;
5201 if(this.inputEl().dom.selectionEnd > 0){
5202 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
5204 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
5205 event.preventDefault();
5210 if(isSelectAll){ // backspace and delete key
5212 event.preventDefault();
5213 // this is very hacky as keydown always get's upper case.
5215 var cc = String.fromCharCode(event.getCharCode());
5216 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
5220 adjustWidth : function(tag, w){
5221 tag = tag.toLowerCase();
5222 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
5223 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
5227 if(tag == 'textarea'){
5230 }else if(Roo.isOpera){
5234 if(tag == 'textarea'){
5253 * @class Roo.bootstrap.TextArea
5254 * @extends Roo.bootstrap.Input
5255 * Bootstrap TextArea class
5256 * @cfg {Number} cols Specifies the visible width of a text area
5257 * @cfg {Number} rows Specifies the visible number of lines in a text area
5258 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
5259 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
5260 * @cfg {string} html text
5263 * Create a new TextArea
5264 * @param {Object} config The config object
5267 Roo.bootstrap.TextArea = function(config){
5268 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
5272 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
5282 getAutoCreate : function(){
5284 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
5295 value : this.value || '',
5296 html: this.html || '',
5297 cls : 'form-control',
5298 placeholder : this.placeholder || ''
5302 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
5303 input.maxLength = this.maxLength;
5307 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
5311 input.cols = this.cols;
5314 if (this.readOnly) {
5315 input.readonly = true;
5319 input.name = this.name;
5323 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
5327 ['xs','sm','md','lg'].map(function(size){
5328 if (settings[size]) {
5329 cfg.cls += ' col-' + size + '-' + settings[size];
5333 var inputblock = input;
5335 if (this.before || this.after) {
5338 cls : 'input-group',
5342 inputblock.cn.push({
5344 cls : 'input-group-addon',
5348 inputblock.cn.push(input);
5350 inputblock.cn.push({
5352 cls : 'input-group-addon',
5359 if (align ==='left' && this.fieldLabel.length) {
5360 Roo.log("left and has label");
5366 cls : 'control-label col-sm-' + this.labelWidth,
5367 html : this.fieldLabel
5371 cls : "col-sm-" + (12 - this.labelWidth),
5378 } else if ( this.fieldLabel.length) {
5384 //cls : 'input-group-addon',
5385 html : this.fieldLabel
5395 Roo.log(" no label && no align");
5405 if (this.disabled) {
5406 input.disabled=true;
5413 * return the real textarea element.
5415 inputEl: function ()
5417 return this.el.select('textarea.form-control',true).first();
5425 * trigger field - base class for combo..
5430 * @class Roo.bootstrap.TriggerField
5431 * @extends Roo.bootstrap.Input
5432 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
5433 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
5434 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
5435 * for which you can provide a custom implementation. For example:
5437 var trigger = new Roo.bootstrap.TriggerField();
5438 trigger.onTriggerClick = myTriggerFn;
5439 trigger.applyTo('my-field');
5442 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
5443 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
5444 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
5445 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
5447 * Create a new TriggerField.
5448 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
5449 * to the base TextField)
5451 Roo.bootstrap.TriggerField = function(config){
5452 this.mimicing = false;
5453 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
5456 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
5458 * @cfg {String} triggerClass A CSS class to apply to the trigger
5461 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
5465 /** @cfg {Boolean} grow @hide */
5466 /** @cfg {Number} growMin @hide */
5467 /** @cfg {Number} growMax @hide */
5473 autoSize: Roo.emptyFn,
5480 actionMode : 'wrap',
5484 getAutoCreate : function(){
5486 var parent = this.parent();
5488 var align = this.parentLabelAlign();
5493 cls: 'form-group' //input-group
5500 type : this.inputType,
5501 cls : 'form-control',
5502 autocomplete: 'off',
5503 placeholder : this.placeholder || ''
5507 input.name = this.name;
5510 input.cls += ' input-' + this.size;
5513 if (this.disabled) {
5514 input.disabled=true;
5517 var inputblock = input;
5519 if (this.before || this.after) {
5522 cls : 'input-group',
5526 inputblock.cn.push({
5528 cls : 'input-group-addon',
5532 inputblock.cn.push(input);
5534 inputblock.cn.push({
5536 cls : 'input-group-addon',
5549 cls: 'form-hidden-field'
5557 Roo.log('multiple');
5565 cls: 'form-hidden-field'
5569 cls: 'select2-choices',
5573 cls: 'select2-search-field',
5586 cls: 'select2-container input-group',
5591 cls: 'typeahead typeahead-long dropdown-menu',
5592 style: 'display:none'
5600 cls : 'input-group-addon btn dropdown-toggle',
5608 cls: 'combobox-clear',
5622 combobox.cls += ' select2-container-multi';
5625 if (align ==='left' && this.fieldLabel.length) {
5627 Roo.log("left and has label");
5633 cls : 'control-label col-sm-' + this.labelWidth,
5634 html : this.fieldLabel
5638 cls : "col-sm-" + (12 - this.labelWidth),
5645 } else if ( this.fieldLabel.length) {
5651 //cls : 'input-group-addon',
5652 html : this.fieldLabel
5662 Roo.log(" no label && no align");
5669 ['xs','sm','md','lg'].map(function(size){
5670 if (settings[size]) {
5671 cfg.cls += ' col-' + size + '-' + settings[size];
5682 onResize : function(w, h){
5683 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
5684 // if(typeof w == 'number'){
5685 // var x = w - this.trigger.getWidth();
5686 // this.inputEl().setWidth(this.adjustWidth('input', x));
5687 // this.trigger.setStyle('left', x+'px');
5692 adjustSize : Roo.BoxComponent.prototype.adjustSize,
5695 getResizeEl : function(){
5696 return this.inputEl();
5700 getPositionEl : function(){
5701 return this.inputEl();
5705 alignErrorIcon : function(){
5706 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
5710 initEvents : function(){
5712 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
5713 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
5715 this.trigger = this.el.select('span.dropdown-toggle',true).first();
5716 if(this.hideTrigger){
5717 this.trigger.setDisplayed(false);
5719 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
5723 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
5726 //this.trigger.addClassOnOver('x-form-trigger-over');
5727 //this.trigger.addClassOnClick('x-form-trigger-click');
5730 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
5735 initTrigger : function(){
5740 onDestroy : function(){
5742 this.trigger.removeAllListeners();
5743 // this.trigger.remove();
5746 // this.wrap.remove();
5748 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
5752 onFocus : function(){
5753 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
5756 this.wrap.addClass('x-trigger-wrap-focus');
5757 this.mimicing = true;
5758 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
5759 if(this.monitorTab){
5760 this.el.on("keydown", this.checkTab, this);
5767 checkTab : function(e){
5768 if(e.getKey() == e.TAB){
5774 onBlur : function(){
5779 mimicBlur : function(e, t){
5781 if(!this.wrap.contains(t) && this.validateBlur()){
5788 triggerBlur : function(){
5789 this.mimicing = false;
5790 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
5791 if(this.monitorTab){
5792 this.el.un("keydown", this.checkTab, this);
5794 //this.wrap.removeClass('x-trigger-wrap-focus');
5795 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
5799 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
5800 validateBlur : function(e, t){
5805 onDisable : function(){
5806 Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
5808 // this.wrap.addClass('x-item-disabled');
5813 onEnable : function(){
5814 Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
5816 // this.el.removeClass('x-item-disabled');
5821 onShow : function(){
5822 var ae = this.getActionEl();
5825 ae.dom.style.display = '';
5826 ae.dom.style.visibility = 'visible';
5832 onHide : function(){
5833 var ae = this.getActionEl();
5834 ae.dom.style.display = 'none';
5838 * The function that should handle the trigger's click event. This method does nothing by default until overridden
5839 * by an implementing function.
5841 * @param {EventObject} e
5843 onTriggerClick : Roo.emptyFn
5847 * Ext JS Library 1.1.1
5848 * Copyright(c) 2006-2007, Ext JS, LLC.
5850 * Originally Released Under LGPL - original licence link has changed is not relivant.
5853 * <script type="text/javascript">
5858 * @class Roo.data.SortTypes
5860 * Defines the default sorting (casting?) comparison functions used when sorting data.
5862 Roo.data.SortTypes = {
5864 * Default sort that does nothing
5865 * @param {Mixed} s The value being converted
5866 * @return {Mixed} The comparison value
5873 * The regular expression used to strip tags
5877 stripTagsRE : /<\/?[^>]+>/gi,
5880 * Strips all HTML tags to sort on text only
5881 * @param {Mixed} s The value being converted
5882 * @return {String} The comparison value
5884 asText : function(s){
5885 return String(s).replace(this.stripTagsRE, "");
5889 * Strips all HTML tags to sort on text only - Case insensitive
5890 * @param {Mixed} s The value being converted
5891 * @return {String} The comparison value
5893 asUCText : function(s){
5894 return String(s).toUpperCase().replace(this.stripTagsRE, "");
5898 * Case insensitive string
5899 * @param {Mixed} s The value being converted
5900 * @return {String} The comparison value
5902 asUCString : function(s) {
5903 return String(s).toUpperCase();
5908 * @param {Mixed} s The value being converted
5909 * @return {Number} The comparison value
5911 asDate : function(s) {
5915 if(s instanceof Date){
5918 return Date.parse(String(s));
5923 * @param {Mixed} s The value being converted
5924 * @return {Float} The comparison value
5926 asFloat : function(s) {
5927 var val = parseFloat(String(s).replace(/,/g, ""));
5928 if(isNaN(val)) val = 0;
5934 * @param {Mixed} s The value being converted
5935 * @return {Number} The comparison value
5937 asInt : function(s) {
5938 var val = parseInt(String(s).replace(/,/g, ""));
5939 if(isNaN(val)) val = 0;
5944 * Ext JS Library 1.1.1
5945 * Copyright(c) 2006-2007, Ext JS, LLC.
5947 * Originally Released Under LGPL - original licence link has changed is not relivant.
5950 * <script type="text/javascript">
5954 * @class Roo.data.Record
5955 * Instances of this class encapsulate both record <em>definition</em> information, and record
5956 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
5957 * to access Records cached in an {@link Roo.data.Store} object.<br>
5959 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
5960 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
5963 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
5965 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
5966 * {@link #create}. The parameters are the same.
5967 * @param {Array} data An associative Array of data values keyed by the field name.
5968 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
5969 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
5970 * not specified an integer id is generated.
5972 Roo.data.Record = function(data, id){
5973 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
5978 * Generate a constructor for a specific record layout.
5979 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
5980 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
5981 * Each field definition object may contain the following properties: <ul>
5982 * <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,
5983 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
5984 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
5985 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
5986 * is being used, then this is a string containing the javascript expression to reference the data relative to
5987 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
5988 * to the data item relative to the record element. If the mapping expression is the same as the field name,
5989 * this may be omitted.</p></li>
5990 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
5991 * <ul><li>auto (Default, implies no conversion)</li>
5996 * <li>date</li></ul></p></li>
5997 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
5998 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
5999 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
6000 * by the Reader into an object that will be stored in the Record. It is passed the
6001 * following parameters:<ul>
6002 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
6004 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
6006 * <br>usage:<br><pre><code>
6007 var TopicRecord = Roo.data.Record.create(
6008 {name: 'title', mapping: 'topic_title'},
6009 {name: 'author', mapping: 'username'},
6010 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
6011 {name: 'lastPost', mapping: 'post_time', type: 'date'},
6012 {name: 'lastPoster', mapping: 'user2'},
6013 {name: 'excerpt', mapping: 'post_text'}
6016 var myNewRecord = new TopicRecord({
6017 title: 'Do my job please',
6020 lastPost: new Date(),
6021 lastPoster: 'Animal',
6022 excerpt: 'No way dude!'
6024 myStore.add(myNewRecord);
6029 Roo.data.Record.create = function(o){
6031 f.superclass.constructor.apply(this, arguments);
6033 Roo.extend(f, Roo.data.Record);
6034 var p = f.prototype;
6035 p.fields = new Roo.util.MixedCollection(false, function(field){
6038 for(var i = 0, len = o.length; i < len; i++){
6039 p.fields.add(new Roo.data.Field(o[i]));
6041 f.getField = function(name){
6042 return p.fields.get(name);
6047 Roo.data.Record.AUTO_ID = 1000;
6048 Roo.data.Record.EDIT = 'edit';
6049 Roo.data.Record.REJECT = 'reject';
6050 Roo.data.Record.COMMIT = 'commit';
6052 Roo.data.Record.prototype = {
6054 * Readonly flag - true if this record has been modified.
6063 join : function(store){
6068 * Set the named field to the specified value.
6069 * @param {String} name The name of the field to set.
6070 * @param {Object} value The value to set the field to.
6072 set : function(name, value){
6073 if(this.data[name] == value){
6080 if(typeof this.modified[name] == 'undefined'){
6081 this.modified[name] = this.data[name];
6083 this.data[name] = value;
6084 if(!this.editing && this.store){
6085 this.store.afterEdit(this);
6090 * Get the value of the named field.
6091 * @param {String} name The name of the field to get the value of.
6092 * @return {Object} The value of the field.
6094 get : function(name){
6095 return this.data[name];
6099 beginEdit : function(){
6100 this.editing = true;
6105 cancelEdit : function(){
6106 this.editing = false;
6107 delete this.modified;
6111 endEdit : function(){
6112 this.editing = false;
6113 if(this.dirty && this.store){
6114 this.store.afterEdit(this);
6119 * Usually called by the {@link Roo.data.Store} which owns the Record.
6120 * Rejects all changes made to the Record since either creation, or the last commit operation.
6121 * Modified fields are reverted to their original values.
6123 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
6124 * of reject operations.
6126 reject : function(){
6127 var m = this.modified;
6129 if(typeof m[n] != "function"){
6130 this.data[n] = m[n];
6134 delete this.modified;
6135 this.editing = false;
6137 this.store.afterReject(this);
6142 * Usually called by the {@link Roo.data.Store} which owns the Record.
6143 * Commits all changes made to the Record since either creation, or the last commit operation.
6145 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
6146 * of commit operations.
6148 commit : function(){
6150 delete this.modified;
6151 this.editing = false;
6153 this.store.afterCommit(this);
6158 hasError : function(){
6159 return this.error != null;
6163 clearError : function(){
6168 * Creates a copy of this record.
6169 * @param {String} id (optional) A new record id if you don't want to use this record's id
6172 copy : function(newId) {
6173 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
6177 * Ext JS Library 1.1.1
6178 * Copyright(c) 2006-2007, Ext JS, LLC.
6180 * Originally Released Under LGPL - original licence link has changed is not relivant.
6183 * <script type="text/javascript">
6189 * @class Roo.data.Store
6190 * @extends Roo.util.Observable
6191 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
6192 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
6194 * 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
6195 * has no knowledge of the format of the data returned by the Proxy.<br>
6197 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
6198 * instances from the data object. These records are cached and made available through accessor functions.
6200 * Creates a new Store.
6201 * @param {Object} config A config object containing the objects needed for the Store to access data,
6202 * and read the data into Records.
6204 Roo.data.Store = function(config){
6205 this.data = new Roo.util.MixedCollection(false);
6206 this.data.getKey = function(o){
6209 this.baseParams = {};
6216 "multisort" : "_multisort"
6219 if(config && config.data){
6220 this.inlineData = config.data;
6224 Roo.apply(this, config);
6226 if(this.reader){ // reader passed
6227 this.reader = Roo.factory(this.reader, Roo.data);
6228 this.reader.xmodule = this.xmodule || false;
6229 if(!this.recordType){
6230 this.recordType = this.reader.recordType;
6232 if(this.reader.onMetaChange){
6233 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
6237 if(this.recordType){
6238 this.fields = this.recordType.prototype.fields;
6244 * @event datachanged
6245 * Fires when the data cache has changed, and a widget which is using this Store
6246 * as a Record cache should refresh its view.
6247 * @param {Store} this
6252 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
6253 * @param {Store} this
6254 * @param {Object} meta The JSON metadata
6259 * Fires when Records have been added to the Store
6260 * @param {Store} this
6261 * @param {Roo.data.Record[]} records The array of Records added
6262 * @param {Number} index The index at which the record(s) were added
6267 * Fires when a Record has been removed from the Store
6268 * @param {Store} this
6269 * @param {Roo.data.Record} record The Record that was removed
6270 * @param {Number} index The index at which the record was removed
6275 * Fires when a Record has been updated
6276 * @param {Store} this
6277 * @param {Roo.data.Record} record The Record that was updated
6278 * @param {String} operation The update operation being performed. Value may be one of:
6280 Roo.data.Record.EDIT
6281 Roo.data.Record.REJECT
6282 Roo.data.Record.COMMIT
6288 * Fires when the data cache has been cleared.
6289 * @param {Store} this
6294 * Fires before a request is made for a new data object. If the beforeload handler returns false
6295 * the load action will be canceled.
6296 * @param {Store} this
6297 * @param {Object} options The loading options that were specified (see {@link #load} for details)
6301 * @event beforeloadadd
6302 * Fires after a new set of Records has been loaded.
6303 * @param {Store} this
6304 * @param {Roo.data.Record[]} records The Records that were loaded
6305 * @param {Object} options The loading options that were specified (see {@link #load} for details)
6307 beforeloadadd : true,
6310 * Fires after a new set of Records has been loaded, before they are added to the store.
6311 * @param {Store} this
6312 * @param {Roo.data.Record[]} records The Records that were loaded
6313 * @param {Object} options The loading options that were specified (see {@link #load} for details)
6314 * @params {Object} return from reader
6318 * @event loadexception
6319 * Fires if an exception occurs in the Proxy during loading.
6320 * Called with the signature of the Proxy's "loadexception" event.
6321 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
6324 * @param {Object} return from JsonData.reader() - success, totalRecords, records
6325 * @param {Object} load options
6326 * @param {Object} jsonData from your request (normally this contains the Exception)
6328 loadexception : true
6332 this.proxy = Roo.factory(this.proxy, Roo.data);
6333 this.proxy.xmodule = this.xmodule || false;
6334 this.relayEvents(this.proxy, ["loadexception"]);
6336 this.sortToggle = {};
6337 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
6339 Roo.data.Store.superclass.constructor.call(this);
6341 if(this.inlineData){
6342 this.loadData(this.inlineData);
6343 delete this.inlineData;
6347 Roo.extend(Roo.data.Store, Roo.util.Observable, {
6349 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
6350 * without a remote query - used by combo/forms at present.
6354 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
6357 * @cfg {Array} data Inline data to be loaded when the store is initialized.
6360 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
6361 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
6364 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
6365 * on any HTTP request
6368 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
6371 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
6375 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
6376 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
6381 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
6382 * loaded or when a record is removed. (defaults to false).
6384 pruneModifiedRecords : false,
6390 * Add Records to the Store and fires the add event.
6391 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
6393 add : function(records){
6394 records = [].concat(records);
6395 for(var i = 0, len = records.length; i < len; i++){
6396 records[i].join(this);
6398 var index = this.data.length;
6399 this.data.addAll(records);
6400 this.fireEvent("add", this, records, index);
6404 * Remove a Record from the Store and fires the remove event.
6405 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
6407 remove : function(record){
6408 var index = this.data.indexOf(record);
6409 this.data.removeAt(index);
6410 if(this.pruneModifiedRecords){
6411 this.modified.remove(record);
6413 this.fireEvent("remove", this, record, index);
6417 * Remove all Records from the Store and fires the clear event.
6419 removeAll : function(){
6421 if(this.pruneModifiedRecords){
6424 this.fireEvent("clear", this);
6428 * Inserts Records to the Store at the given index and fires the add event.
6429 * @param {Number} index The start index at which to insert the passed Records.
6430 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
6432 insert : function(index, records){
6433 records = [].concat(records);
6434 for(var i = 0, len = records.length; i < len; i++){
6435 this.data.insert(index, records[i]);
6436 records[i].join(this);
6438 this.fireEvent("add", this, records, index);
6442 * Get the index within the cache of the passed Record.
6443 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
6444 * @return {Number} The index of the passed Record. Returns -1 if not found.
6446 indexOf : function(record){
6447 return this.data.indexOf(record);
6451 * Get the index within the cache of the Record with the passed id.
6452 * @param {String} id The id of the Record to find.
6453 * @return {Number} The index of the Record. Returns -1 if not found.
6455 indexOfId : function(id){
6456 return this.data.indexOfKey(id);
6460 * Get the Record with the specified id.
6461 * @param {String} id The id of the Record to find.
6462 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
6464 getById : function(id){
6465 return this.data.key(id);
6469 * Get the Record at the specified index.
6470 * @param {Number} index The index of the Record to find.
6471 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
6473 getAt : function(index){
6474 return this.data.itemAt(index);
6478 * Returns a range of Records between specified indices.
6479 * @param {Number} startIndex (optional) The starting index (defaults to 0)
6480 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
6481 * @return {Roo.data.Record[]} An array of Records
6483 getRange : function(start, end){
6484 return this.data.getRange(start, end);
6488 storeOptions : function(o){
6489 o = Roo.apply({}, o);
6492 this.lastOptions = o;
6496 * Loads the Record cache from the configured Proxy using the configured Reader.
6498 * If using remote paging, then the first load call must specify the <em>start</em>
6499 * and <em>limit</em> properties in the options.params property to establish the initial
6500 * position within the dataset, and the number of Records to cache on each read from the Proxy.
6502 * <strong>It is important to note that for remote data sources, loading is asynchronous,
6503 * and this call will return before the new data has been loaded. Perform any post-processing
6504 * in a callback function, or in a "load" event handler.</strong>
6506 * @param {Object} options An object containing properties which control loading options:<ul>
6507 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
6508 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
6509 * passed the following arguments:<ul>
6510 * <li>r : Roo.data.Record[]</li>
6511 * <li>options: Options object from the load call</li>
6512 * <li>success: Boolean success indicator</li></ul></li>
6513 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
6514 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
6517 load : function(options){
6518 options = options || {};
6519 if(this.fireEvent("beforeload", this, options) !== false){
6520 this.storeOptions(options);
6521 var p = Roo.apply(options.params || {}, this.baseParams);
6522 // if meta was not loaded from remote source.. try requesting it.
6523 if (!this.reader.metaFromRemote) {
6526 if(this.sortInfo && this.remoteSort){
6527 var pn = this.paramNames;
6528 p[pn["sort"]] = this.sortInfo.field;
6529 p[pn["dir"]] = this.sortInfo.direction;
6531 if (this.multiSort) {
6532 var pn = this.paramNames;
6533 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
6536 this.proxy.load(p, this.reader, this.loadRecords, this, options);
6541 * Reloads the Record cache from the configured Proxy using the configured Reader and
6542 * the options from the last load operation performed.
6543 * @param {Object} options (optional) An object containing properties which may override the options
6544 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
6545 * the most recently used options are reused).
6547 reload : function(options){
6548 this.load(Roo.applyIf(options||{}, this.lastOptions));
6552 // Called as a callback by the Reader during a load operation.
6553 loadRecords : function(o, options, success){
6554 if(!o || success === false){
6555 if(success !== false){
6556 this.fireEvent("load", this, [], options, o);
6558 if(options.callback){
6559 options.callback.call(options.scope || this, [], options, false);
6563 // if data returned failure - throw an exception.
6564 if (o.success === false) {
6565 // show a message if no listener is registered.
6566 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
6567 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
6569 // loadmask wil be hooked into this..
6570 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
6573 var r = o.records, t = o.totalRecords || r.length;
6575 this.fireEvent("beforeloadadd", this, r, options, o);
6577 if(!options || options.add !== true){
6578 if(this.pruneModifiedRecords){
6581 for(var i = 0, len = r.length; i < len; i++){
6585 this.data = this.snapshot;
6586 delete this.snapshot;
6589 this.data.addAll(r);
6590 this.totalLength = t;
6592 this.fireEvent("datachanged", this);
6594 this.totalLength = Math.max(t, this.data.length+r.length);
6597 this.fireEvent("load", this, r, options, o);
6598 if(options.callback){
6599 options.callback.call(options.scope || this, r, options, true);
6605 * Loads data from a passed data block. A Reader which understands the format of the data
6606 * must have been configured in the constructor.
6607 * @param {Object} data The data block from which to read the Records. The format of the data expected
6608 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
6609 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
6611 loadData : function(o, append){
6612 var r = this.reader.readRecords(o);
6613 this.loadRecords(r, {add: append}, true);
6617 * Gets the number of cached records.
6619 * <em>If using paging, this may not be the total size of the dataset. If the data object
6620 * used by the Reader contains the dataset size, then the getTotalCount() function returns
6621 * the data set size</em>
6623 getCount : function(){
6624 return this.data.length || 0;
6628 * Gets the total number of records in the dataset as returned by the server.
6630 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
6631 * the dataset size</em>
6633 getTotalCount : function(){
6634 return this.totalLength || 0;
6638 * Returns the sort state of the Store as an object with two properties:
6640 field {String} The name of the field by which the Records are sorted
6641 direction {String} The sort order, "ASC" or "DESC"
6644 getSortState : function(){
6645 return this.sortInfo;
6649 applySort : function(){
6650 if(this.sortInfo && !this.remoteSort){
6651 var s = this.sortInfo, f = s.field;
6652 var st = this.fields.get(f).sortType;
6653 var fn = function(r1, r2){
6654 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
6655 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
6657 this.data.sort(s.direction, fn);
6658 if(this.snapshot && this.snapshot != this.data){
6659 this.snapshot.sort(s.direction, fn);
6665 * Sets the default sort column and order to be used by the next load operation.
6666 * @param {String} fieldName The name of the field to sort by.
6667 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
6669 setDefaultSort : function(field, dir){
6670 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
6675 * If remote sorting is used, the sort is performed on the server, and the cache is
6676 * reloaded. If local sorting is used, the cache is sorted internally.
6677 * @param {String} fieldName The name of the field to sort by.
6678 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
6680 sort : function(fieldName, dir){
6681 var f = this.fields.get(fieldName);
6683 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
6685 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
6686 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
6691 this.sortToggle[f.name] = dir;
6692 this.sortInfo = {field: f.name, direction: dir};
6693 if(!this.remoteSort){
6695 this.fireEvent("datachanged", this);
6697 this.load(this.lastOptions);
6702 * Calls the specified function for each of the Records in the cache.
6703 * @param {Function} fn The function to call. The Record is passed as the first parameter.
6704 * Returning <em>false</em> aborts and exits the iteration.
6705 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
6707 each : function(fn, scope){
6708 this.data.each(fn, scope);
6712 * Gets all records modified since the last commit. Modified records are persisted across load operations
6713 * (e.g., during paging).
6714 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
6716 getModifiedRecords : function(){
6717 return this.modified;
6721 createFilterFn : function(property, value, anyMatch){
6722 if(!value.exec){ // not a regex
6723 value = String(value);
6724 if(value.length == 0){
6727 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
6730 return value.test(r.data[property]);
6735 * Sums the value of <i>property</i> for each record between start and end and returns the result.
6736 * @param {String} property A field on your records
6737 * @param {Number} start The record index to start at (defaults to 0)
6738 * @param {Number} end The last record index to include (defaults to length - 1)
6739 * @return {Number} The sum
6741 sum : function(property, start, end){
6742 var rs = this.data.items, v = 0;
6744 end = (end || end === 0) ? end : rs.length-1;
6746 for(var i = start; i <= end; i++){
6747 v += (rs[i].data[property] || 0);
6753 * Filter the records by a specified property.
6754 * @param {String} field A field on your records
6755 * @param {String/RegExp} value Either a string that the field
6756 * should start with or a RegExp to test against the field
6757 * @param {Boolean} anyMatch True to match any part not just the beginning
6759 filter : function(property, value, anyMatch){
6760 var fn = this.createFilterFn(property, value, anyMatch);
6761 return fn ? this.filterBy(fn) : this.clearFilter();
6765 * Filter by a function. The specified function will be called with each
6766 * record in this data source. If the function returns true the record is included,
6767 * otherwise it is filtered.
6768 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
6769 * @param {Object} scope (optional) The scope of the function (defaults to this)
6771 filterBy : function(fn, scope){
6772 this.snapshot = this.snapshot || this.data;
6773 this.data = this.queryBy(fn, scope||this);
6774 this.fireEvent("datachanged", this);
6778 * Query the records by a specified property.
6779 * @param {String} field A field on your records
6780 * @param {String/RegExp} value Either a string that the field
6781 * should start with or a RegExp to test against the field
6782 * @param {Boolean} anyMatch True to match any part not just the beginning
6783 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
6785 query : function(property, value, anyMatch){
6786 var fn = this.createFilterFn(property, value, anyMatch);
6787 return fn ? this.queryBy(fn) : this.data.clone();
6791 * Query by a function. The specified function will be called with each
6792 * record in this data source. If the function returns true the record is included
6794 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
6795 * @param {Object} scope (optional) The scope of the function (defaults to this)
6796 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
6798 queryBy : function(fn, scope){
6799 var data = this.snapshot || this.data;
6800 return data.filterBy(fn, scope||this);
6804 * Collects unique values for a particular dataIndex from this store.
6805 * @param {String} dataIndex The property to collect
6806 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
6807 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
6808 * @return {Array} An array of the unique values
6810 collect : function(dataIndex, allowNull, bypassFilter){
6811 var d = (bypassFilter === true && this.snapshot) ?
6812 this.snapshot.items : this.data.items;
6813 var v, sv, r = [], l = {};
6814 for(var i = 0, len = d.length; i < len; i++){
6815 v = d[i].data[dataIndex];
6817 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
6826 * Revert to a view of the Record cache with no filtering applied.
6827 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
6829 clearFilter : function(suppressEvent){
6830 if(this.snapshot && this.snapshot != this.data){
6831 this.data = this.snapshot;
6832 delete this.snapshot;
6833 if(suppressEvent !== true){
6834 this.fireEvent("datachanged", this);
6840 afterEdit : function(record){
6841 if(this.modified.indexOf(record) == -1){
6842 this.modified.push(record);
6844 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
6848 afterReject : function(record){
6849 this.modified.remove(record);
6850 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
6854 afterCommit : function(record){
6855 this.modified.remove(record);
6856 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
6860 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
6861 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
6863 commitChanges : function(){
6864 var m = this.modified.slice(0);
6866 for(var i = 0, len = m.length; i < len; i++){
6872 * Cancel outstanding changes on all changed records.
6874 rejectChanges : function(){
6875 var m = this.modified.slice(0);
6877 for(var i = 0, len = m.length; i < len; i++){
6882 onMetaChange : function(meta, rtype, o){
6883 this.recordType = rtype;
6884 this.fields = rtype.prototype.fields;
6885 delete this.snapshot;
6886 this.sortInfo = meta.sortInfo || this.sortInfo;
6888 this.fireEvent('metachange', this, this.reader.meta);
6891 moveIndex : function(data, type)
6893 var index = this.indexOf(data);
6895 var newIndex = index + type;
6899 this.insert(newIndex, data);
6904 * Ext JS Library 1.1.1
6905 * Copyright(c) 2006-2007, Ext JS, LLC.
6907 * Originally Released Under LGPL - original licence link has changed is not relivant.
6910 * <script type="text/javascript">
6914 * @class Roo.data.SimpleStore
6915 * @extends Roo.data.Store
6916 * Small helper class to make creating Stores from Array data easier.
6917 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
6918 * @cfg {Array} fields An array of field definition objects, or field name strings.
6919 * @cfg {Array} data The multi-dimensional array of data
6921 * @param {Object} config
6923 Roo.data.SimpleStore = function(config){
6924 Roo.data.SimpleStore.superclass.constructor.call(this, {
6926 reader: new Roo.data.ArrayReader({
6929 Roo.data.Record.create(config.fields)
6931 proxy : new Roo.data.MemoryProxy(config.data)
6935 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
6937 * Ext JS Library 1.1.1
6938 * Copyright(c) 2006-2007, Ext JS, LLC.
6940 * Originally Released Under LGPL - original licence link has changed is not relivant.
6943 * <script type="text/javascript">
6948 * @extends Roo.data.Store
6949 * @class Roo.data.JsonStore
6950 * Small helper class to make creating Stores for JSON data easier. <br/>
6952 var store = new Roo.data.JsonStore({
6953 url: 'get-images.php',
6955 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
6958 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
6959 * JsonReader and HttpProxy (unless inline data is provided).</b>
6960 * @cfg {Array} fields An array of field definition objects, or field name strings.
6962 * @param {Object} config
6964 Roo.data.JsonStore = function(c){
6965 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
6966 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
6967 reader: new Roo.data.JsonReader(c, c.fields)
6970 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
6972 * Ext JS Library 1.1.1
6973 * Copyright(c) 2006-2007, Ext JS, LLC.
6975 * Originally Released Under LGPL - original licence link has changed is not relivant.
6978 * <script type="text/javascript">
6982 Roo.data.Field = function(config){
6983 if(typeof config == "string"){
6984 config = {name: config};
6986 Roo.apply(this, config);
6992 var st = Roo.data.SortTypes;
6993 // named sortTypes are supported, here we look them up
6994 if(typeof this.sortType == "string"){
6995 this.sortType = st[this.sortType];
6998 // set default sortType for strings and dates
7002 this.sortType = st.asUCString;
7005 this.sortType = st.asDate;
7008 this.sortType = st.none;
7013 var stripRe = /[\$,%]/g;
7015 // prebuilt conversion function for this field, instead of
7016 // switching every time we're reading a value
7018 var cv, dateFormat = this.dateFormat;
7023 cv = function(v){ return v; };
7026 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
7030 return v !== undefined && v !== null && v !== '' ?
7031 parseInt(String(v).replace(stripRe, ""), 10) : '';
7036 return v !== undefined && v !== null && v !== '' ?
7037 parseFloat(String(v).replace(stripRe, ""), 10) : '';
7042 cv = function(v){ return v === true || v === "true" || v == 1; };
7049 if(v instanceof Date){
7053 if(dateFormat == "timestamp"){
7054 return new Date(v*1000);
7056 return Date.parseDate(v, dateFormat);
7058 var parsed = Date.parse(v);
7059 return parsed ? new Date(parsed) : null;
7068 Roo.data.Field.prototype = {
7076 * Ext JS Library 1.1.1
7077 * Copyright(c) 2006-2007, Ext JS, LLC.
7079 * Originally Released Under LGPL - original licence link has changed is not relivant.
7082 * <script type="text/javascript">
7085 // Base class for reading structured data from a data source. This class is intended to be
7086 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
7089 * @class Roo.data.DataReader
7090 * Base class for reading structured data from a data source. This class is intended to be
7091 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
7094 Roo.data.DataReader = function(meta, recordType){
7098 this.recordType = recordType instanceof Array ?
7099 Roo.data.Record.create(recordType) : recordType;
7102 Roo.data.DataReader.prototype = {
7104 * Create an empty record
7105 * @param {Object} data (optional) - overlay some values
7106 * @return {Roo.data.Record} record created.
7108 newRow : function(d) {
7110 this.recordType.prototype.fields.each(function(c) {
7112 case 'int' : da[c.name] = 0; break;
7113 case 'date' : da[c.name] = new Date(); break;
7114 case 'float' : da[c.name] = 0.0; break;
7115 case 'boolean' : da[c.name] = false; break;
7116 default : da[c.name] = ""; break;
7120 return new this.recordType(Roo.apply(da, d));
7125 * Ext JS Library 1.1.1
7126 * Copyright(c) 2006-2007, Ext JS, LLC.
7128 * Originally Released Under LGPL - original licence link has changed is not relivant.
7131 * <script type="text/javascript">
7135 * @class Roo.data.DataProxy
7136 * @extends Roo.data.Observable
7137 * This class is an abstract base class for implementations which provide retrieval of
7138 * unformatted data objects.<br>
7140 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
7141 * (of the appropriate type which knows how to parse the data object) to provide a block of
7142 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
7144 * Custom implementations must implement the load method as described in
7145 * {@link Roo.data.HttpProxy#load}.
7147 Roo.data.DataProxy = function(){
7151 * Fires before a network request is made to retrieve a data object.
7152 * @param {Object} This DataProxy object.
7153 * @param {Object} params The params parameter to the load function.
7158 * Fires before the load method's callback is called.
7159 * @param {Object} This DataProxy object.
7160 * @param {Object} o The data object.
7161 * @param {Object} arg The callback argument object passed to the load function.
7165 * @event loadexception
7166 * Fires if an Exception occurs during data retrieval.
7167 * @param {Object} This DataProxy object.
7168 * @param {Object} o The data object.
7169 * @param {Object} arg The callback argument object passed to the load function.
7170 * @param {Object} e The Exception.
7172 loadexception : true
7174 Roo.data.DataProxy.superclass.constructor.call(this);
7177 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
7180 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
7184 * Ext JS Library 1.1.1
7185 * Copyright(c) 2006-2007, Ext JS, LLC.
7187 * Originally Released Under LGPL - original licence link has changed is not relivant.
7190 * <script type="text/javascript">
7193 * @class Roo.data.MemoryProxy
7194 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
7195 * to the Reader when its load method is called.
7197 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
7199 Roo.data.MemoryProxy = function(data){
7203 Roo.data.MemoryProxy.superclass.constructor.call(this);
7207 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
7209 * Load data from the requested source (in this case an in-memory
7210 * data object passed to the constructor), read the data object into
7211 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
7212 * process that block using the passed callback.
7213 * @param {Object} params This parameter is not used by the MemoryProxy class.
7214 * @param {Roo.data.DataReader} reader The Reader object which converts the data
7215 * object into a block of Roo.data.Records.
7216 * @param {Function} callback The function into which to pass the block of Roo.data.records.
7217 * The function must be passed <ul>
7218 * <li>The Record block object</li>
7219 * <li>The "arg" argument from the load function</li>
7220 * <li>A boolean success indicator</li>
7222 * @param {Object} scope The scope in which to call the callback
7223 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
7225 load : function(params, reader, callback, scope, arg){
7226 params = params || {};
7229 result = reader.readRecords(this.data);
7231 this.fireEvent("loadexception", this, arg, null, e);
7232 callback.call(scope, null, arg, false);
7235 callback.call(scope, result, arg, true);
7239 update : function(params, records){
7244 * Ext JS Library 1.1.1
7245 * Copyright(c) 2006-2007, Ext JS, LLC.
7247 * Originally Released Under LGPL - original licence link has changed is not relivant.
7250 * <script type="text/javascript">
7253 * @class Roo.data.HttpProxy
7254 * @extends Roo.data.DataProxy
7255 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
7256 * configured to reference a certain URL.<br><br>
7258 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
7259 * from which the running page was served.<br><br>
7261 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
7263 * Be aware that to enable the browser to parse an XML document, the server must set
7264 * the Content-Type header in the HTTP response to "text/xml".
7266 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
7267 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
7268 * will be used to make the request.
7270 Roo.data.HttpProxy = function(conn){
7271 Roo.data.HttpProxy.superclass.constructor.call(this);
7272 // is conn a conn config or a real conn?
7274 this.useAjax = !conn || !conn.events;
7278 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
7279 // thse are take from connection...
7282 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
7285 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
7286 * extra parameters to each request made by this object. (defaults to undefined)
7289 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
7290 * to each request made by this object. (defaults to undefined)
7293 * @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)
7296 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
7299 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
7305 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
7309 * Return the {@link Roo.data.Connection} object being used by this Proxy.
7310 * @return {Connection} The Connection object. This object may be used to subscribe to events on
7311 * a finer-grained basis than the DataProxy events.
7313 getConnection : function(){
7314 return this.useAjax ? Roo.Ajax : this.conn;
7318 * Load data from the configured {@link Roo.data.Connection}, read the data object into
7319 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
7320 * process that block using the passed callback.
7321 * @param {Object} params An object containing properties which are to be used as HTTP parameters
7322 * for the request to the remote server.
7323 * @param {Roo.data.DataReader} reader The Reader object which converts the data
7324 * object into a block of Roo.data.Records.
7325 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
7326 * The function must be passed <ul>
7327 * <li>The Record block object</li>
7328 * <li>The "arg" argument from the load function</li>
7329 * <li>A boolean success indicator</li>
7331 * @param {Object} scope The scope in which to call the callback
7332 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
7334 load : function(params, reader, callback, scope, arg){
7335 if(this.fireEvent("beforeload", this, params) !== false){
7337 params : params || {},
7339 callback : callback,
7344 callback : this.loadResponse,
7348 Roo.applyIf(o, this.conn);
7349 if(this.activeRequest){
7350 Roo.Ajax.abort(this.activeRequest);
7352 this.activeRequest = Roo.Ajax.request(o);
7354 this.conn.request(o);
7357 callback.call(scope||this, null, arg, false);
7362 loadResponse : function(o, success, response){
7363 delete this.activeRequest;
7365 this.fireEvent("loadexception", this, o, response);
7366 o.request.callback.call(o.request.scope, null, o.request.arg, false);
7371 result = o.reader.read(response);
7373 this.fireEvent("loadexception", this, o, response, e);
7374 o.request.callback.call(o.request.scope, null, o.request.arg, false);
7378 this.fireEvent("load", this, o, o.request.arg);
7379 o.request.callback.call(o.request.scope, result, o.request.arg, true);
7383 update : function(dataSet){
7388 updateResponse : function(dataSet){
7393 * Ext JS Library 1.1.1
7394 * Copyright(c) 2006-2007, Ext JS, LLC.
7396 * Originally Released Under LGPL - original licence link has changed is not relivant.
7399 * <script type="text/javascript">
7403 * @class Roo.data.ScriptTagProxy
7404 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
7405 * other than the originating domain of the running page.<br><br>
7407 * <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
7408 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
7410 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
7411 * source code that is used as the source inside a <script> tag.<br><br>
7413 * In order for the browser to process the returned data, the server must wrap the data object
7414 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
7415 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
7416 * depending on whether the callback name was passed:
7419 boolean scriptTag = false;
7420 String cb = request.getParameter("callback");
7423 response.setContentType("text/javascript");
7425 response.setContentType("application/x-json");
7427 Writer out = response.getWriter();
7429 out.write(cb + "(");
7431 out.print(dataBlock.toJsonString());
7438 * @param {Object} config A configuration object.
7440 Roo.data.ScriptTagProxy = function(config){
7441 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
7442 Roo.apply(this, config);
7443 this.head = document.getElementsByTagName("head")[0];
7446 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
7448 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
7450 * @cfg {String} url The URL from which to request the data object.
7453 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
7457 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
7458 * the server the name of the callback function set up by the load call to process the returned data object.
7459 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
7460 * javascript output which calls this named function passing the data object as its only parameter.
7462 callbackParam : "callback",
7464 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
7465 * name to the request.
7470 * Load data from the configured URL, read the data object into
7471 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
7472 * process that block using the passed callback.
7473 * @param {Object} params An object containing properties which are to be used as HTTP parameters
7474 * for the request to the remote server.
7475 * @param {Roo.data.DataReader} reader The Reader object which converts the data
7476 * object into a block of Roo.data.Records.
7477 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
7478 * The function must be passed <ul>
7479 * <li>The Record block object</li>
7480 * <li>The "arg" argument from the load function</li>
7481 * <li>A boolean success indicator</li>
7483 * @param {Object} scope The scope in which to call the callback
7484 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
7486 load : function(params, reader, callback, scope, arg){
7487 if(this.fireEvent("beforeload", this, params) !== false){
7489 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
7492 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
7494 url += "&_dc=" + (new Date().getTime());
7496 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
7499 cb : "stcCallback"+transId,
7500 scriptId : "stcScript"+transId,
7504 callback : callback,
7510 window[trans.cb] = function(o){
7511 conn.handleResponse(o, trans);
7514 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
7516 if(this.autoAbort !== false){
7520 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
7522 var script = document.createElement("script");
7523 script.setAttribute("src", url);
7524 script.setAttribute("type", "text/javascript");
7525 script.setAttribute("id", trans.scriptId);
7526 this.head.appendChild(script);
7530 callback.call(scope||this, null, arg, false);
7535 isLoading : function(){
7536 return this.trans ? true : false;
7540 * Abort the current server request.
7543 if(this.isLoading()){
7544 this.destroyTrans(this.trans);
7549 destroyTrans : function(trans, isLoaded){
7550 this.head.removeChild(document.getElementById(trans.scriptId));
7551 clearTimeout(trans.timeoutId);
7553 window[trans.cb] = undefined;
7555 delete window[trans.cb];
7558 // if hasn't been loaded, wait for load to remove it to prevent script error
7559 window[trans.cb] = function(){
7560 window[trans.cb] = undefined;
7562 delete window[trans.cb];
7569 handleResponse : function(o, trans){
7571 this.destroyTrans(trans, true);
7574 result = trans.reader.readRecords(o);
7576 this.fireEvent("loadexception", this, o, trans.arg, e);
7577 trans.callback.call(trans.scope||window, null, trans.arg, false);
7580 this.fireEvent("load", this, o, trans.arg);
7581 trans.callback.call(trans.scope||window, result, trans.arg, true);
7585 handleFailure : function(trans){
7587 this.destroyTrans(trans, false);
7588 this.fireEvent("loadexception", this, null, trans.arg);
7589 trans.callback.call(trans.scope||window, null, trans.arg, false);
7593 * Ext JS Library 1.1.1
7594 * Copyright(c) 2006-2007, Ext JS, LLC.
7596 * Originally Released Under LGPL - original licence link has changed is not relivant.
7599 * <script type="text/javascript">
7603 * @class Roo.data.JsonReader
7604 * @extends Roo.data.DataReader
7605 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
7606 * based on mappings in a provided Roo.data.Record constructor.
7608 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
7609 * in the reply previously.
7614 var RecordDef = Roo.data.Record.create([
7615 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
7616 {name: 'occupation'} // This field will use "occupation" as the mapping.
7618 var myReader = new Roo.data.JsonReader({
7619 totalProperty: "results", // The property which contains the total dataset size (optional)
7620 root: "rows", // The property which contains an Array of row objects
7621 id: "id" // The property within each row object that provides an ID for the record (optional)
7625 * This would consume a JSON file like this:
7627 { 'results': 2, 'rows': [
7628 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
7629 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
7632 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
7633 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
7634 * paged from the remote server.
7635 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
7636 * @cfg {String} root name of the property which contains the Array of row objects.
7637 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
7639 * Create a new JsonReader
7640 * @param {Object} meta Metadata configuration options
7641 * @param {Object} recordType Either an Array of field definition objects,
7642 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
7644 Roo.data.JsonReader = function(meta, recordType){
7647 // set some defaults:
7649 totalProperty: 'total',
7650 successProperty : 'success',
7655 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
7657 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
7660 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
7661 * Used by Store query builder to append _requestMeta to params.
7664 metaFromRemote : false,
7666 * This method is only used by a DataProxy which has retrieved data from a remote server.
7667 * @param {Object} response The XHR object which contains the JSON data in its responseText.
7668 * @return {Object} data A data block which is used by an Roo.data.Store object as
7669 * a cache of Roo.data.Records.
7671 read : function(response){
7672 var json = response.responseText;
7674 var o = /* eval:var:o */ eval("("+json+")");
7676 throw {message: "JsonReader.read: Json object not found"};
7682 this.metaFromRemote = true;
7683 this.meta = o.metaData;
7684 this.recordType = Roo.data.Record.create(o.metaData.fields);
7685 this.onMetaChange(this.meta, this.recordType, o);
7687 return this.readRecords(o);
7690 // private function a store will implement
7691 onMetaChange : function(meta, recordType, o){
7698 simpleAccess: function(obj, subsc) {
7705 getJsonAccessor: function(){
7707 return function(expr) {
7709 return(re.test(expr))
7710 ? new Function("obj", "return obj." + expr)
7720 * Create a data block containing Roo.data.Records from an XML document.
7721 * @param {Object} o An object which contains an Array of row objects in the property specified
7722 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
7723 * which contains the total size of the dataset.
7724 * @return {Object} data A data block which is used by an Roo.data.Store object as
7725 * a cache of Roo.data.Records.
7727 readRecords : function(o){
7729 * After any data loads, the raw JSON data is available for further custom processing.
7733 var s = this.meta, Record = this.recordType,
7734 f = Record.prototype.fields, fi = f.items, fl = f.length;
7736 // Generate extraction functions for the totalProperty, the root, the id, and for each field
7738 if(s.totalProperty) {
7739 this.getTotal = this.getJsonAccessor(s.totalProperty);
7741 if(s.successProperty) {
7742 this.getSuccess = this.getJsonAccessor(s.successProperty);
7744 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
7746 var g = this.getJsonAccessor(s.id);
7747 this.getId = function(rec) {
7749 return (r === undefined || r === "") ? null : r;
7752 this.getId = function(){return null;};
7755 for(var jj = 0; jj < fl; jj++){
7757 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
7758 this.ef[jj] = this.getJsonAccessor(map);
7762 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
7763 if(s.totalProperty){
7764 var vt = parseInt(this.getTotal(o), 10);
7769 if(s.successProperty){
7770 var vs = this.getSuccess(o);
7771 if(vs === false || vs === 'false'){
7776 for(var i = 0; i < c; i++){
7779 var id = this.getId(n);
7780 for(var j = 0; j < fl; j++){
7782 var v = this.ef[j](n);
7784 Roo.log('missing convert for ' + f.name);
7788 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
7790 var record = new Record(values, id);
7792 records[i] = record;
7798 totalRecords : totalRecords
7803 * Ext JS Library 1.1.1
7804 * Copyright(c) 2006-2007, Ext JS, LLC.
7806 * Originally Released Under LGPL - original licence link has changed is not relivant.
7809 * <script type="text/javascript">
7813 * @class Roo.data.ArrayReader
7814 * @extends Roo.data.DataReader
7815 * Data reader class to create an Array of Roo.data.Record objects from an Array.
7816 * Each element of that Array represents a row of data fields. The
7817 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
7818 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
7822 var RecordDef = Roo.data.Record.create([
7823 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
7824 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
7826 var myReader = new Roo.data.ArrayReader({
7827 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
7831 * This would consume an Array like this:
7833 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
7835 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
7837 * Create a new JsonReader
7838 * @param {Object} meta Metadata configuration options.
7839 * @param {Object} recordType Either an Array of field definition objects
7840 * as specified to {@link Roo.data.Record#create},
7841 * or an {@link Roo.data.Record} object
7842 * created using {@link Roo.data.Record#create}.
7844 Roo.data.ArrayReader = function(meta, recordType){
7845 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
7848 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
7850 * Create a data block containing Roo.data.Records from an XML document.
7851 * @param {Object} o An Array of row objects which represents the dataset.
7852 * @return {Object} data A data block which is used by an Roo.data.Store object as
7853 * a cache of Roo.data.Records.
7855 readRecords : function(o){
7856 var sid = this.meta ? this.meta.id : null;
7857 var recordType = this.recordType, fields = recordType.prototype.fields;
7860 for(var i = 0; i < root.length; i++){
7863 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
7864 for(var j = 0, jlen = fields.length; j < jlen; j++){
7865 var f = fields.items[j];
7866 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
7867 var v = n[k] !== undefined ? n[k] : f.defaultValue;
7871 var record = new recordType(values, id);
7873 records[records.length] = record;
7877 totalRecords : records.length
7886 * @class Roo.bootstrap.ComboBox
7887 * @extends Roo.bootstrap.TriggerField
7888 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
7889 * @cfg {Boolean} append (true|false) default false
7891 * Create a new ComboBox.
7892 * @param {Object} config Configuration options
7894 Roo.bootstrap.ComboBox = function(config){
7895 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
7899 * Fires when the dropdown list is expanded
7900 * @param {Roo.bootstrap.ComboBox} combo This combo box
7905 * Fires when the dropdown list is collapsed
7906 * @param {Roo.bootstrap.ComboBox} combo This combo box
7910 * @event beforeselect
7911 * Fires before a list item is selected. Return false to cancel the selection.
7912 * @param {Roo.bootstrap.ComboBox} combo This combo box
7913 * @param {Roo.data.Record} record The data record returned from the underlying store
7914 * @param {Number} index The index of the selected item in the dropdown list
7916 'beforeselect' : true,
7919 * Fires when a list item is selected
7920 * @param {Roo.bootstrap.ComboBox} combo This combo box
7921 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
7922 * @param {Number} index The index of the selected item in the dropdown list
7926 * @event beforequery
7927 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
7928 * The event object passed has these properties:
7929 * @param {Roo.bootstrap.ComboBox} combo This combo box
7930 * @param {String} query The query
7931 * @param {Boolean} forceAll true to force "all" query
7932 * @param {Boolean} cancel true to cancel the query
7933 * @param {Object} e The query event object
7935 'beforequery': true,
7938 * Fires when the 'add' icon is pressed (add a listener to enable add button)
7939 * @param {Roo.bootstrap.ComboBox} combo This combo box
7944 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
7945 * @param {Roo.bootstrap.ComboBox} combo This combo box
7946 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
7951 * Fires when the remove value from the combobox array
7952 * @param {Roo.bootstrap.ComboBox} combo This combo box
7959 this.selectedIndex = -1;
7960 if(this.mode == 'local'){
7961 if(config.queryDelay === undefined){
7962 this.queryDelay = 10;
7964 if(config.minChars === undefined){
7970 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
7973 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
7974 * rendering into an Roo.Editor, defaults to false)
7977 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
7978 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
7981 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
7984 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
7985 * the dropdown list (defaults to undefined, with no header element)
7989 * @cfg {String/Roo.Template} tpl The template to use to render the output
7993 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
7995 listWidth: undefined,
7997 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
7998 * mode = 'remote' or 'text' if mode = 'local')
8000 displayField: undefined,
8002 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
8003 * mode = 'remote' or 'value' if mode = 'local').
8004 * Note: use of a valueField requires the user make a selection
8005 * in order for a value to be mapped.
8007 valueField: undefined,
8011 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
8012 * field's data value (defaults to the underlying DOM element's name)
8014 hiddenName: undefined,
8016 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
8020 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
8022 selectedClass: 'active',
8025 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
8029 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
8030 * anchor positions (defaults to 'tl-bl')
8032 listAlign: 'tl-bl?',
8034 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
8038 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
8039 * query specified by the allQuery config option (defaults to 'query')
8041 triggerAction: 'query',
8043 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
8044 * (defaults to 4, does not apply if editable = false)
8048 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
8049 * delay (typeAheadDelay) if it matches a known value (defaults to false)
8053 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
8054 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
8058 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
8059 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
8063 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
8064 * when editable = true (defaults to false)
8066 selectOnFocus:false,
8068 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
8070 queryParam: 'query',
8072 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
8073 * when mode = 'remote' (defaults to 'Loading...')
8075 loadingText: 'Loading...',
8077 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
8081 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
8085 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
8086 * traditional select (defaults to true)
8090 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
8094 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
8098 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
8099 * listWidth has a higher value)
8103 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
8104 * allow the user to set arbitrary text into the field (defaults to false)
8106 forceSelection:false,
8108 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
8109 * if typeAhead = true (defaults to 250)
8111 typeAheadDelay : 250,
8113 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
8114 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
8116 valueNotFoundText : undefined,
8118 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
8123 * @cfg {Boolean} disableClear Disable showing of clear button.
8125 disableClear : false,
8127 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
8129 alwaysQuery : false,
8132 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
8146 // element that contains real text value.. (when hidden is used..)
8149 initEvents: function(){
8152 throw "can not find store for combo";
8154 this.store = Roo.factory(this.store, Roo.data);
8158 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
8161 if(this.hiddenName){
8163 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
8165 this.hiddenField.dom.value =
8166 this.hiddenValue !== undefined ? this.hiddenValue :
8167 this.value !== undefined ? this.value : '';
8169 // prevent input submission
8170 this.el.dom.removeAttribute('name');
8171 this.hiddenField.dom.setAttribute('name', this.hiddenName);
8176 // this.el.dom.setAttribute('autocomplete', 'off');
8179 var cls = 'x-combo-list';
8180 this.list = this.el.select('ul.dropdown-menu',true).first();
8182 //this.list = new Roo.Layer({
8183 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
8186 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
8187 this.list.setWidth(lw);
8189 this.list.on('mouseover', this.onViewOver, this);
8190 this.list.on('mousemove', this.onViewMove, this);
8192 this.list.on('scroll', this.onViewScroll, this);
8195 this.list.swallowEvent('mousewheel');
8196 this.assetHeight = 0;
8199 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
8200 this.assetHeight += this.header.getHeight();
8203 this.innerList = this.list.createChild({cls:cls+'-inner'});
8204 this.innerList.on('mouseover', this.onViewOver, this);
8205 this.innerList.on('mousemove', this.onViewMove, this);
8206 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
8208 if(this.allowBlank && !this.pageSize && !this.disableClear){
8209 this.footer = this.list.createChild({cls:cls+'-ft'});
8210 this.pageTb = new Roo.Toolbar(this.footer);
8214 this.footer = this.list.createChild({cls:cls+'-ft'});
8215 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
8216 {pageSize: this.pageSize});
8220 if (this.pageTb && this.allowBlank && !this.disableClear) {
8222 this.pageTb.add(new Roo.Toolbar.Fill(), {
8223 cls: 'x-btn-icon x-btn-clear',
8229 _this.onSelect(false, -1);
8234 this.assetHeight += this.footer.getHeight();
8239 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
8242 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
8243 singleSelect:true, store: this.store, selectedClass: this.selectedClass
8245 //this.view.wrapEl.setDisplayed(false);
8246 this.view.on('click', this.onViewClick, this);
8250 this.store.on('beforeload', this.onBeforeLoad, this);
8251 this.store.on('load', this.onLoad, this);
8252 this.store.on('loadexception', this.onLoadException, this);
8255 this.resizer = new Roo.Resizable(this.list, {
8256 pinned:true, handles:'se'
8258 this.resizer.on('resize', function(r, w, h){
8259 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
8261 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
8262 this.restrictHeight();
8264 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
8268 this.editable = true;
8269 this.setEditable(false);
8274 if (typeof(this.events.add.listeners) != 'undefined') {
8276 this.addicon = this.wrap.createChild(
8277 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
8279 this.addicon.on('click', function(e) {
8280 this.fireEvent('add', this);
8283 if (typeof(this.events.edit.listeners) != 'undefined') {
8285 this.editicon = this.wrap.createChild(
8286 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
8288 this.editicon.setStyle('margin-left', '40px');
8290 this.editicon.on('click', function(e) {
8292 // we fire even if inothing is selected..
8293 this.fireEvent('edit', this, this.lastData );
8299 this.keyNav = new Roo.KeyNav(this.inputEl(), {
8301 this.inKeyMode = true;
8305 "down" : function(e){
8306 if(!this.isExpanded()){
8307 this.onTriggerClick();
8309 this.inKeyMode = true;
8314 "enter" : function(e){
8319 "esc" : function(e){
8323 "tab" : function(e){
8326 if(this.fireEvent("specialkey", this, e)){
8327 this.onViewClick(false);
8335 doRelay : function(foo, bar, hname){
8336 if(hname == 'down' || this.scope.isExpanded()){
8337 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
8346 this.queryDelay = Math.max(this.queryDelay || 10,
8347 this.mode == 'local' ? 10 : 250);
8350 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
8353 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
8355 if(this.editable !== false){
8356 this.inputEl().on("keyup", this.onKeyUp, this);
8358 if(this.forceSelection){
8359 this.on('blur', this.doForce, this);
8363 this.choices = this.el.select('ul.select2-choices', true).first();
8364 this.searchField = this.el.select('ul li.select2-search-field', true).first();
8368 onDestroy : function(){
8370 this.view.setStore(null);
8371 this.view.el.removeAllListeners();
8372 this.view.el.remove();
8373 this.view.purgeListeners();
8376 this.list.dom.innerHTML = '';
8379 this.store.un('beforeload', this.onBeforeLoad, this);
8380 this.store.un('load', this.onLoad, this);
8381 this.store.un('loadexception', this.onLoadException, this);
8383 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
8387 fireKey : function(e){
8388 if(e.isNavKeyPress() && !this.list.isVisible()){
8389 this.fireEvent("specialkey", this, e);
8394 onResize: function(w, h){
8395 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
8397 // if(typeof w != 'number'){
8398 // // we do not handle it!?!?
8401 // var tw = this.trigger.getWidth();
8402 // // tw += this.addicon ? this.addicon.getWidth() : 0;
8403 // // tw += this.editicon ? this.editicon.getWidth() : 0;
8405 // this.inputEl().setWidth( this.adjustWidth('input', x));
8407 // //this.trigger.setStyle('left', x+'px');
8409 // if(this.list && this.listWidth === undefined){
8410 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
8411 // this.list.setWidth(lw);
8412 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
8420 * Allow or prevent the user from directly editing the field text. If false is passed,
8421 * the user will only be able to select from the items defined in the dropdown list. This method
8422 * is the runtime equivalent of setting the 'editable' config option at config time.
8423 * @param {Boolean} value True to allow the user to directly edit the field text
8425 setEditable : function(value){
8426 if(value == this.editable){
8429 this.editable = value;
8431 this.inputEl().dom.setAttribute('readOnly', true);
8432 this.inputEl().on('mousedown', this.onTriggerClick, this);
8433 this.inputEl().addClass('x-combo-noedit');
8435 this.inputEl().dom.setAttribute('readOnly', false);
8436 this.inputEl().un('mousedown', this.onTriggerClick, this);
8437 this.inputEl().removeClass('x-combo-noedit');
8443 onBeforeLoad : function(combo,opts){
8448 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
8450 this.restrictHeight();
8451 this.selectedIndex = -1;
8455 onLoad : function(){
8457 this.hasQuery = false;
8463 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
8464 this.loading.hide();
8467 if(this.store.getCount() > 0){
8469 this.restrictHeight();
8470 if(this.lastQuery == this.allQuery){
8472 this.inputEl().dom.select();
8474 if(!this.selectByValue(this.value, true)){
8475 this.select(0, true);
8479 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
8480 this.taTask.delay(this.typeAheadDelay);
8484 this.onEmptyResults();
8490 onLoadException : function()
8492 this.hasQuery = false;
8494 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
8495 this.loading.hide();
8499 Roo.log(this.store.reader.jsonData);
8500 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
8502 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
8508 onTypeAhead : function(){
8509 if(this.store.getCount() > 0){
8510 var r = this.store.getAt(0);
8511 var newValue = r.data[this.displayField];
8512 var len = newValue.length;
8513 var selStart = this.getRawValue().length;
8515 if(selStart != len){
8516 this.setRawValue(newValue);
8517 this.selectText(selStart, newValue.length);
8523 onSelect : function(record, index){
8525 if(this.fireEvent('beforeselect', this, record, index) !== false){
8527 this.setFromData(index > -1 ? record.data : false);
8530 this.fireEvent('select', this, record, index);
8535 * Returns the currently selected field value or empty string if no value is set.
8536 * @return {String} value The selected value
8538 getValue : function(){
8541 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
8544 if(this.valueField){
8545 return typeof this.value != 'undefined' ? this.value : '';
8547 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
8552 * Clears any text/value currently set in the field
8554 clearValue : function(){
8555 if(this.hiddenField){
8556 this.hiddenField.dom.value = '';
8559 this.setRawValue('');
8560 this.lastSelectionText = '';
8565 * Sets the specified value into the field. If the value finds a match, the corresponding record text
8566 * will be displayed in the field. If the value does not match the data value of an existing item,
8567 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
8568 * Otherwise the field will be blank (although the value will still be set).
8569 * @param {String} value The value to match
8571 setValue : function(v){
8578 if(this.valueField){
8579 var r = this.findRecord(this.valueField, v);
8581 text = r.data[this.displayField];
8582 }else if(this.valueNotFoundText !== undefined){
8583 text = this.valueNotFoundText;
8586 this.lastSelectionText = text;
8587 if(this.hiddenField){
8588 this.hiddenField.dom.value = v;
8590 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
8594 * @property {Object} the last set data for the element
8599 * Sets the value of the field based on a object which is related to the record format for the store.
8600 * @param {Object} value the value to set as. or false on reset?
8602 setFromData : function(o){
8609 var dv = ''; // display value
8610 var vv = ''; // value value..
8612 if (this.displayField) {
8613 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
8615 // this is an error condition!!!
8616 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
8619 if(this.valueField){
8620 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
8623 if(this.hiddenField){
8624 this.hiddenField.dom.value = vv;
8626 this.lastSelectionText = dv;
8627 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
8631 // no hidden field.. - we store the value in 'value', but still display
8632 // display field!!!!
8633 this.lastSelectionText = dv;
8634 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
8641 // overridden so that last data is reset..
8642 this.setValue(this.originalValue);
8643 this.clearInvalid();
8644 this.lastData = false;
8646 this.view.clearSelections();
8650 findRecord : function(prop, value){
8652 if(this.store.getCount() > 0){
8653 this.store.each(function(r){
8654 if(r.data[prop] == value){
8666 // returns hidden if it's set..
8667 if (!this.rendered) {return ''};
8668 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
8672 onViewMove : function(e, t){
8673 this.inKeyMode = false;
8677 onViewOver : function(e, t){
8678 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
8681 var item = this.view.findItemFromChild(t);
8683 var index = this.view.indexOf(item);
8684 this.select(index, false);
8689 onViewClick : function(doFocus)
8691 var index = this.view.getSelectedIndexes()[0];
8692 var r = this.store.getAt(index);
8694 this.onSelect(r, index);
8696 if(doFocus !== false && !this.blockFocus){
8697 this.inputEl().focus();
8702 restrictHeight : function(){
8703 //this.innerList.dom.style.height = '';
8704 //var inner = this.innerList.dom;
8705 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
8706 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
8707 //this.list.beginUpdate();
8708 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
8709 this.list.alignTo(this.inputEl(), this.listAlign);
8710 //this.list.endUpdate();
8714 onEmptyResults : function(){
8719 * Returns true if the dropdown list is expanded, else false.
8721 isExpanded : function(){
8722 return this.list.isVisible();
8726 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
8727 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
8728 * @param {String} value The data value of the item to select
8729 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
8730 * selected item if it is not currently in view (defaults to true)
8731 * @return {Boolean} True if the value matched an item in the list, else false
8733 selectByValue : function(v, scrollIntoView){
8734 if(v !== undefined && v !== null){
8735 var r = this.findRecord(this.valueField || this.displayField, v);
8737 this.select(this.store.indexOf(r), scrollIntoView);
8745 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
8746 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
8747 * @param {Number} index The zero-based index of the list item to select
8748 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
8749 * selected item if it is not currently in view (defaults to true)
8751 select : function(index, scrollIntoView){
8752 this.selectedIndex = index;
8753 this.view.select(index);
8754 if(scrollIntoView !== false){
8755 var el = this.view.getNode(index);
8757 //this.innerList.scrollChildIntoView(el, false);
8764 selectNext : function(){
8765 var ct = this.store.getCount();
8767 if(this.selectedIndex == -1){
8769 }else if(this.selectedIndex < ct-1){
8770 this.select(this.selectedIndex+1);
8776 selectPrev : function(){
8777 var ct = this.store.getCount();
8779 if(this.selectedIndex == -1){
8781 }else if(this.selectedIndex != 0){
8782 this.select(this.selectedIndex-1);
8788 onKeyUp : function(e){
8789 if(this.editable !== false && !e.isSpecialKey()){
8790 this.lastKey = e.getKey();
8791 this.dqTask.delay(this.queryDelay);
8796 validateBlur : function(){
8797 return !this.list || !this.list.isVisible();
8801 initQuery : function(){
8802 this.doQuery(this.getRawValue());
8806 doForce : function(){
8807 if(this.el.dom.value.length > 0){
8809 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
8815 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
8816 * query allowing the query action to be canceled if needed.
8817 * @param {String} query The SQL query to execute
8818 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
8819 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
8820 * saved in the current store (defaults to false)
8822 doQuery : function(q, forceAll){
8824 if(q === undefined || q === null){
8833 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
8838 forceAll = qe.forceAll;
8839 if(forceAll === true || (q.length >= this.minChars)){
8841 this.hasQuery = true;
8843 if(this.lastQuery != q || this.alwaysQuery){
8845 if(this.mode == 'local'){
8846 this.selectedIndex = -1;
8848 this.store.clearFilter();
8850 this.store.filter(this.displayField, q);
8854 this.store.baseParams[this.queryParam] = q;
8856 var options = {params : this.getParams(q)};
8860 options.params.start = this.page * this.pageSize;
8863 this.store.load(options);
8867 this.selectedIndex = -1;
8872 this.loadNext = false;
8876 getParams : function(q){
8878 //p[this.queryParam] = q;
8882 p.limit = this.pageSize;
8888 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
8890 collapse : function(){
8891 if(!this.isExpanded()){
8896 Roo.get(document).un('mousedown', this.collapseIf, this);
8897 Roo.get(document).un('mousewheel', this.collapseIf, this);
8898 if (!this.editable) {
8899 Roo.get(document).un('keydown', this.listKeyPress, this);
8901 this.fireEvent('collapse', this);
8905 collapseIf : function(e){
8906 var in_combo = e.within(this.el);
8907 var in_list = e.within(this.list);
8909 if (in_combo || in_list) {
8910 //e.stopPropagation();
8919 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
8921 expand : function(){
8923 if(this.isExpanded() || !this.hasFocus){
8927 this.list.alignTo(this.inputEl(), this.listAlign);
8929 Roo.get(document).on('mousedown', this.collapseIf, this);
8930 Roo.get(document).on('mousewheel', this.collapseIf, this);
8931 if (!this.editable) {
8932 Roo.get(document).on('keydown', this.listKeyPress, this);
8935 this.fireEvent('expand', this);
8939 // Implements the default empty TriggerField.onTriggerClick function
8940 onTriggerClick : function()
8942 Roo.log('trigger click');
8949 this.loadNext = false;
8951 if(this.isExpanded()){
8953 if (!this.blockFocus) {
8954 this.inputEl().focus();
8958 this.hasFocus = true;
8959 if(this.triggerAction == 'all') {
8960 this.doQuery(this.allQuery, true);
8962 this.doQuery(this.getRawValue());
8964 if (!this.blockFocus) {
8965 this.inputEl().focus();
8969 listKeyPress : function(e)
8971 //Roo.log('listkeypress');
8972 // scroll to first matching element based on key pres..
8973 if (e.isSpecialKey()) {
8976 var k = String.fromCharCode(e.getKey()).toUpperCase();
8979 var csel = this.view.getSelectedNodes();
8980 var cselitem = false;
8982 var ix = this.view.indexOf(csel[0]);
8983 cselitem = this.store.getAt(ix);
8984 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
8990 this.store.each(function(v) {
8992 // start at existing selection.
8993 if (cselitem.id == v.id) {
8999 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
9000 match = this.store.indexOf(v);
9006 if (match === false) {
9007 return true; // no more action?
9010 this.view.select(match);
9011 var sn = Roo.get(this.view.getSelectedNodes()[0])
9012 //sn.scrollIntoView(sn.dom.parentNode, false);
9015 onViewScroll : function(e, t){
9017 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
9021 this.hasQuery = true;
9023 this.loading = this.list.select('.loading', true).first();
9025 if(this.loading === null){
9026 this.list.createChild({
9028 cls: 'loading select2-more-results select2-active',
9029 html: 'Loading more results...'
9032 this.loading = this.list.select('.loading', true).first();
9034 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
9036 this.loading.hide();
9039 this.loading.show();
9044 this.loadNext = true;
9046 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
9051 addItem : function(o)
9053 var dv = ''; // display value
9055 if (this.displayField) {
9056 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
9058 // this is an error condition!!!
9059 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
9066 var choice = this.choices.createChild({
9068 cls: 'select2-search-choice',
9077 cls: 'select2-search-choice-close',
9082 }, this.searchField);
9084 var close = choice.select('a.select2-search-choice-close', true).first()
9086 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
9093 this.inputEl().dom.value = '';
9097 onRemoveItem : function(e, _self, o)
9099 Roo.log('remove item');
9100 var index = this.item.indexOf(o.data) * 1;
9103 Roo.log('not this item?!');
9107 this.item.splice(index, 1);
9112 this.fireEvent('remove', this);
9116 syncValue : function()
9118 if(!this.item.length){
9125 Roo.each(this.item, function(i){
9126 if(_this.valueField){
9127 value.push(i[_this.valueField]);
9134 this.value = value.join(',');
9136 if(this.hiddenField){
9137 this.hiddenField.dom.value = this.value;
9141 clearItem : function()
9149 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
9159 * @cfg {Boolean} grow
9163 * @cfg {Number} growMin
9167 * @cfg {Number} growMax
9177 * Ext JS Library 1.1.1
9178 * Copyright(c) 2006-2007, Ext JS, LLC.
9180 * Originally Released Under LGPL - original licence link has changed is not relivant.
9183 * <script type="text/javascript">
9188 * @extends Roo.util.Observable
9189 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
9190 * This class also supports single and multi selection modes. <br>
9191 * Create a data model bound view:
9193 var store = new Roo.data.Store(...);
9195 var view = new Roo.View({
9197 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
9200 selectedClass: "ydataview-selected",
9204 // listen for node click?
9205 view.on("click", function(vw, index, node, e){
9206 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9210 dataModel.load("foobar.xml");
9212 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
9214 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
9215 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
9217 * Note: old style constructor is still suported (container, template, config)
9221 * @param {Object} config The config object
9224 Roo.View = function(config, depreciated_tpl, depreciated_config){
9226 if (typeof(depreciated_tpl) == 'undefined') {
9227 // new way.. - universal constructor.
9228 Roo.apply(this, config);
9229 this.el = Roo.get(this.el);
9232 this.el = Roo.get(config);
9233 this.tpl = depreciated_tpl;
9234 Roo.apply(this, depreciated_config);
9236 this.wrapEl = this.el.wrap().wrap();
9237 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
9240 if(typeof(this.tpl) == "string"){
9241 this.tpl = new Roo.Template(this.tpl);
9243 // support xtype ctors..
9244 this.tpl = new Roo.factory(this.tpl, Roo);
9256 * @event beforeclick
9257 * Fires before a click is processed. Returns false to cancel the default action.
9258 * @param {Roo.View} this
9259 * @param {Number} index The index of the target node
9260 * @param {HTMLElement} node The target node
9261 * @param {Roo.EventObject} e The raw event object
9263 "beforeclick" : true,
9266 * Fires when a template node is clicked.
9267 * @param {Roo.View} this
9268 * @param {Number} index The index of the target node
9269 * @param {HTMLElement} node The target node
9270 * @param {Roo.EventObject} e The raw event object
9275 * Fires when a template node is double clicked.
9276 * @param {Roo.View} this
9277 * @param {Number} index The index of the target node
9278 * @param {HTMLElement} node The target node
9279 * @param {Roo.EventObject} e The raw event object
9283 * @event contextmenu
9284 * Fires when a template node is right clicked.
9285 * @param {Roo.View} this
9286 * @param {Number} index The index of the target node
9287 * @param {HTMLElement} node The target node
9288 * @param {Roo.EventObject} e The raw event object
9290 "contextmenu" : true,
9292 * @event selectionchange
9293 * Fires when the selected nodes change.
9294 * @param {Roo.View} this
9295 * @param {Array} selections Array of the selected nodes
9297 "selectionchange" : true,
9300 * @event beforeselect
9301 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
9302 * @param {Roo.View} this
9303 * @param {HTMLElement} node The node to be selected
9304 * @param {Array} selections Array of currently selected nodes
9306 "beforeselect" : true,
9308 * @event preparedata
9309 * Fires on every row to render, to allow you to change the data.
9310 * @param {Roo.View} this
9311 * @param {Object} data to be rendered (change this)
9313 "preparedata" : true
9321 "click": this.onClick,
9322 "dblclick": this.onDblClick,
9323 "contextmenu": this.onContextMenu,
9327 this.selections = [];
9329 this.cmp = new Roo.CompositeElementLite([]);
9331 this.store = Roo.factory(this.store, Roo.data);
9332 this.setStore(this.store, true);
9335 if ( this.footer && this.footer.xtype) {
9337 var fctr = this.wrapEl.appendChild(document.createElement("div"));
9339 this.footer.dataSource = this.store
9340 this.footer.container = fctr;
9341 this.footer = Roo.factory(this.footer, Roo);
9342 fctr.insertFirst(this.el);
9344 // this is a bit insane - as the paging toolbar seems to detach the el..
9345 // dom.parentNode.parentNode.parentNode
9346 // they get detached?
9350 Roo.View.superclass.constructor.call(this);
9355 Roo.extend(Roo.View, Roo.util.Observable, {
9358 * @cfg {Roo.data.Store} store Data store to load data from.
9363 * @cfg {String|Roo.Element} el The container element.
9368 * @cfg {String|Roo.Template} tpl The template used by this View
9372 * @cfg {String} dataName the named area of the template to use as the data area
9373 * Works with domtemplates roo-name="name"
9377 * @cfg {String} selectedClass The css class to add to selected nodes
9379 selectedClass : "x-view-selected",
9381 * @cfg {String} emptyText The empty text to show when nothing is loaded.
9386 * @cfg {String} text to display on mask (default Loading)
9390 * @cfg {Boolean} multiSelect Allow multiple selection
9392 multiSelect : false,
9394 * @cfg {Boolean} singleSelect Allow single selection
9396 singleSelect: false,
9399 * @cfg {Boolean} toggleSelect - selecting
9401 toggleSelect : false,
9404 * Returns the element this view is bound to.
9405 * @return {Roo.Element}
9414 * Refreshes the view. - called by datachanged on the store. - do not call directly.
9416 refresh : function(){
9420 // if we are using something like 'domtemplate', then
9421 // the what gets used is:
9422 // t.applySubtemplate(NAME, data, wrapping data..)
9423 // the outer template then get' applied with
9424 // the store 'extra data'
9425 // and the body get's added to the
9426 // roo-name="data" node?
9427 // <span class='roo-tpl-{name}'></span> ?????
9431 this.clearSelections();
9434 var records = this.store.getRange();
9435 if(records.length < 1) {
9437 // is this valid?? = should it render a template??
9439 this.el.update(this.emptyText);
9443 if (this.dataName) {
9444 this.el.update(t.apply(this.store.meta)); //????
9445 el = this.el.child('.roo-tpl-' + this.dataName);
9448 for(var i = 0, len = records.length; i < len; i++){
9449 var data = this.prepareData(records[i].data, i, records[i]);
9450 this.fireEvent("preparedata", this, data, i, records[i]);
9451 html[html.length] = Roo.util.Format.trim(
9453 t.applySubtemplate(this.dataName, data, this.store.meta) :
9460 el.update(html.join(""));
9461 this.nodes = el.dom.childNodes;
9462 this.updateIndexes(0);
9467 * Function to override to reformat the data that is sent to
9468 * the template for each node.
9469 * DEPRICATED - use the preparedata event handler.
9470 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
9471 * a JSON object for an UpdateManager bound view).
9473 prepareData : function(data, index, record)
9475 this.fireEvent("preparedata", this, data, index, record);
9479 onUpdate : function(ds, record){
9480 Roo.log('on update');
9481 this.clearSelections();
9482 var index = this.store.indexOf(record);
9483 var n = this.nodes[index];
9484 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
9485 n.parentNode.removeChild(n);
9486 this.updateIndexes(index, index);
9492 onAdd : function(ds, records, index)
9494 Roo.log(['on Add', ds, records, index] );
9495 this.clearSelections();
9496 if(this.nodes.length == 0){
9500 var n = this.nodes[index];
9501 for(var i = 0, len = records.length; i < len; i++){
9502 var d = this.prepareData(records[i].data, i, records[i]);
9504 this.tpl.insertBefore(n, d);
9507 this.tpl.append(this.el, d);
9510 this.updateIndexes(index);
9513 onRemove : function(ds, record, index){
9514 Roo.log('onRemove');
9515 this.clearSelections();
9516 var el = this.dataName ?
9517 this.el.child('.roo-tpl-' + this.dataName) :
9520 el.dom.removeChild(this.nodes[index]);
9521 this.updateIndexes(index);
9525 * Refresh an individual node.
9526 * @param {Number} index
9528 refreshNode : function(index){
9529 this.onUpdate(this.store, this.store.getAt(index));
9532 updateIndexes : function(startIndex, endIndex){
9533 var ns = this.nodes;
9534 startIndex = startIndex || 0;
9535 endIndex = endIndex || ns.length - 1;
9536 for(var i = startIndex; i <= endIndex; i++){
9537 ns[i].nodeIndex = i;
9542 * Changes the data store this view uses and refresh the view.
9543 * @param {Store} store
9545 setStore : function(store, initial){
9546 if(!initial && this.store){
9547 this.store.un("datachanged", this.refresh);
9548 this.store.un("add", this.onAdd);
9549 this.store.un("remove", this.onRemove);
9550 this.store.un("update", this.onUpdate);
9551 this.store.un("clear", this.refresh);
9552 this.store.un("beforeload", this.onBeforeLoad);
9553 this.store.un("load", this.onLoad);
9554 this.store.un("loadexception", this.onLoad);
9558 store.on("datachanged", this.refresh, this);
9559 store.on("add", this.onAdd, this);
9560 store.on("remove", this.onRemove, this);
9561 store.on("update", this.onUpdate, this);
9562 store.on("clear", this.refresh, this);
9563 store.on("beforeload", this.onBeforeLoad, this);
9564 store.on("load", this.onLoad, this);
9565 store.on("loadexception", this.onLoad, this);
9573 * onbeforeLoad - masks the loading area.
9576 onBeforeLoad : function(store,opts)
9578 Roo.log('onBeforeLoad');
9582 this.el.mask(this.mask ? this.mask : "Loading" );
9584 onLoad : function ()
9591 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
9592 * @param {HTMLElement} node
9593 * @return {HTMLElement} The template node
9595 findItemFromChild : function(node){
9596 var el = this.dataName ?
9597 this.el.child('.roo-tpl-' + this.dataName,true) :
9600 if(!node || node.parentNode == el){
9603 var p = node.parentNode;
9604 while(p && p != el){
9605 if(p.parentNode == el){
9614 onClick : function(e){
9615 var item = this.findItemFromChild(e.getTarget());
9617 var index = this.indexOf(item);
9618 if(this.onItemClick(item, index, e) !== false){
9619 this.fireEvent("click", this, index, item, e);
9622 this.clearSelections();
9627 onContextMenu : function(e){
9628 var item = this.findItemFromChild(e.getTarget());
9630 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
9635 onDblClick : function(e){
9636 var item = this.findItemFromChild(e.getTarget());
9638 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
9642 onItemClick : function(item, index, e)
9644 if(this.fireEvent("beforeclick", this, index, item, e) === false){
9647 if (this.toggleSelect) {
9648 var m = this.isSelected(item) ? 'unselect' : 'select';
9651 _t[m](item, true, false);
9654 if(this.multiSelect || this.singleSelect){
9655 if(this.multiSelect && e.shiftKey && this.lastSelection){
9656 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
9658 this.select(item, this.multiSelect && e.ctrlKey);
9659 this.lastSelection = item;
9667 * Get the number of selected nodes.
9670 getSelectionCount : function(){
9671 return this.selections.length;
9675 * Get the currently selected nodes.
9676 * @return {Array} An array of HTMLElements
9678 getSelectedNodes : function(){
9679 return this.selections;
9683 * Get the indexes of the selected nodes.
9686 getSelectedIndexes : function(){
9687 var indexes = [], s = this.selections;
9688 for(var i = 0, len = s.length; i < len; i++){
9689 indexes.push(s[i].nodeIndex);
9695 * Clear all selections
9696 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
9698 clearSelections : function(suppressEvent){
9699 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
9700 this.cmp.elements = this.selections;
9701 this.cmp.removeClass(this.selectedClass);
9702 this.selections = [];
9704 this.fireEvent("selectionchange", this, this.selections);
9710 * Returns true if the passed node is selected
9711 * @param {HTMLElement/Number} node The node or node index
9714 isSelected : function(node){
9715 var s = this.selections;
9719 node = this.getNode(node);
9720 return s.indexOf(node) !== -1;
9725 * @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
9726 * @param {Boolean} keepExisting (optional) true to keep existing selections
9727 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
9729 select : function(nodeInfo, keepExisting, suppressEvent){
9730 if(nodeInfo instanceof Array){
9732 this.clearSelections(true);
9734 for(var i = 0, len = nodeInfo.length; i < len; i++){
9735 this.select(nodeInfo[i], true, true);
9739 var node = this.getNode(nodeInfo);
9740 if(!node || this.isSelected(node)){
9741 return; // already selected.
9744 this.clearSelections(true);
9746 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
9747 Roo.fly(node).addClass(this.selectedClass);
9748 this.selections.push(node);
9750 this.fireEvent("selectionchange", this, this.selections);
9758 * @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
9759 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
9760 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
9762 unselect : function(nodeInfo, keepExisting, suppressEvent)
9764 if(nodeInfo instanceof Array){
9765 Roo.each(this.selections, function(s) {
9766 this.unselect(s, nodeInfo);
9770 var node = this.getNode(nodeInfo);
9771 if(!node || !this.isSelected(node)){
9772 Roo.log("not selected");
9773 return; // not selected.
9777 Roo.each(this.selections, function(s) {
9779 Roo.fly(node).removeClass(this.selectedClass);
9786 this.selections= ns;
9787 this.fireEvent("selectionchange", this, this.selections);
9791 * Gets a template node.
9792 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9793 * @return {HTMLElement} The node or null if it wasn't found
9795 getNode : function(nodeInfo){
9796 if(typeof nodeInfo == "string"){
9797 return document.getElementById(nodeInfo);
9798 }else if(typeof nodeInfo == "number"){
9799 return this.nodes[nodeInfo];
9805 * Gets a range template nodes.
9806 * @param {Number} startIndex
9807 * @param {Number} endIndex
9808 * @return {Array} An array of nodes
9810 getNodes : function(start, end){
9811 var ns = this.nodes;
9813 end = typeof end == "undefined" ? ns.length - 1 : end;
9816 for(var i = start; i <= end; i++){
9820 for(var i = start; i >= end; i--){
9828 * Finds the index of the passed node
9829 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9830 * @return {Number} The index of the node or -1
9832 indexOf : function(node){
9833 node = this.getNode(node);
9834 if(typeof node.nodeIndex == "number"){
9835 return node.nodeIndex;
9837 var ns = this.nodes;
9838 for(var i = 0, len = ns.length; i < len; i++){
9849 * based on jquery fullcalendar
9853 Roo.bootstrap = Roo.bootstrap || {};
9855 * @class Roo.bootstrap.Calendar
9856 * @extends Roo.bootstrap.Component
9857 * Bootstrap Calendar class
9858 * @cfg {Boolean} loadMask (true|false) default false
9861 * Create a new Container
9862 * @param {Object} config The config object
9867 Roo.bootstrap.Calendar = function(config){
9868 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
9872 * Fires when a date is selected
9873 * @param {DatePicker} this
9874 * @param {Date} date The selected date
9878 * @event monthchange
9879 * Fires when the displayed month changes
9880 * @param {DatePicker} this
9881 * @param {Date} date The selected month
9883 'monthchange': true,
9886 * Fires when mouse over an event
9887 * @param {Calendar} this
9888 * @param {event} Event
9893 * Fires when the mouse leaves an
9894 * @param {Calendar} this
9900 * Fires when the mouse click an
9901 * @param {Calendar} this
9910 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
9913 * @cfg {Number} startDay
9914 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
9920 getAutoCreate : function(){
9923 var fc_button = function(name, corner, style, content ) {
9924 return Roo.apply({},{
9926 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
9928 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
9931 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
9939 style : 'width:100%',
9946 cls : 'fc-header-left',
9948 fc_button('prev', 'left', 'arrow', '‹' ),
9949 fc_button('next', 'right', 'arrow', '›' ),
9950 { tag: 'span', cls: 'fc-header-space' },
9951 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
9959 cls : 'fc-header-center',
9963 cls: 'fc-header-title',
9966 html : 'month / year'
9974 cls : 'fc-header-right',
9976 /* fc_button('month', 'left', '', 'month' ),
9977 fc_button('week', '', '', 'week' ),
9978 fc_button('day', 'right', '', 'day' )
9990 var cal_heads = function() {
9992 // fixme - handle this.
9994 for (var i =0; i < Date.dayNames.length; i++) {
9995 var d = Date.dayNames[i];
9998 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
9999 html : d.substring(0,3)
10003 ret[0].cls += ' fc-first';
10004 ret[6].cls += ' fc-last';
10007 var cal_cell = function(n) {
10010 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
10015 cls: 'fc-day-number',
10019 cls: 'fc-day-content',
10023 style: 'position: relative;' // height: 17px;
10035 var cal_rows = function() {
10038 for (var r = 0; r < 6; r++) {
10045 for (var i =0; i < Date.dayNames.length; i++) {
10046 var d = Date.dayNames[i];
10047 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
10050 row.cn[0].cls+=' fc-first';
10051 row.cn[0].cn[0].style = 'min-height:90px';
10052 row.cn[6].cls+=' fc-last';
10056 ret[0].cls += ' fc-first';
10057 ret[4].cls += ' fc-prev-last';
10058 ret[5].cls += ' fc-last';
10065 cls: 'fc-border-separate',
10066 style : 'width:100%',
10074 cls : 'fc-first fc-last',
10092 cls : 'fc-content',
10093 style : "position: relative;",
10096 cls : 'fc-view fc-view-month fc-grid',
10097 style : 'position: relative',
10098 unselectable : 'on',
10101 cls : 'fc-event-container',
10102 style : 'position:absolute;z-index:8;top:0;left:0;'
10120 initEvents : function()
10123 throw "can not find store for calendar";
10129 style: "text-align:center",
10133 style: "background-color:white;width:50%;margin:250 auto",
10137 src: rootURL + '/roojs1/images/ux/lightbox/loading.gif'
10148 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
10150 var size = this.el.select('.fc-content', true).first().getSize();
10151 this.maskEl.setSize(size.width, size.height);
10152 this.maskEl.enableDisplayMode("block");
10153 if(!this.loadMask){
10154 this.maskEl.hide();
10157 this.store = Roo.factory(this.store, Roo.data);
10158 this.store.on('load', this.onLoad, this);
10159 this.store.on('beforeload', this.onBeforeLoad, this);
10163 this.cells = this.el.select('.fc-day',true);
10164 //Roo.log(this.cells);
10165 this.textNodes = this.el.query('.fc-day-number');
10166 this.cells.addClassOnOver('fc-state-hover');
10168 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
10169 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
10170 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
10171 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
10173 this.on('monthchange', this.onMonthChange, this);
10175 this.update(new Date().clearTime());
10178 resize : function() {
10179 var sz = this.el.getSize();
10181 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
10182 this.el.select('.fc-day-content div',true).setHeight(34);
10187 showPrevMonth : function(e){
10188 this.update(this.activeDate.add("mo", -1));
10190 showToday : function(e){
10191 this.update(new Date().clearTime());
10194 showNextMonth : function(e){
10195 this.update(this.activeDate.add("mo", 1));
10199 showPrevYear : function(){
10200 this.update(this.activeDate.add("y", -1));
10204 showNextYear : function(){
10205 this.update(this.activeDate.add("y", 1));
10210 update : function(date)
10212 var vd = this.activeDate;
10213 this.activeDate = date;
10214 // if(vd && this.el){
10215 // var t = date.getTime();
10216 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
10217 // Roo.log('using add remove');
10219 // this.fireEvent('monthchange', this, date);
10221 // this.cells.removeClass("fc-state-highlight");
10222 // this.cells.each(function(c){
10223 // if(c.dateValue == t){
10224 // c.addClass("fc-state-highlight");
10225 // setTimeout(function(){
10226 // try{c.dom.firstChild.focus();}catch(e){}
10236 var days = date.getDaysInMonth();
10238 var firstOfMonth = date.getFirstDateOfMonth();
10239 var startingPos = firstOfMonth.getDay()-this.startDay;
10241 if(startingPos < this.startDay){
10245 var pm = date.add(Date.MONTH, -1);
10246 var prevStart = pm.getDaysInMonth()-startingPos;
10248 this.cells = this.el.select('.fc-day',true);
10249 this.textNodes = this.el.query('.fc-day-number');
10250 this.cells.addClassOnOver('fc-state-hover');
10252 var cells = this.cells.elements;
10253 var textEls = this.textNodes;
10255 Roo.each(cells, function(cell){
10256 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
10259 days += startingPos;
10261 // convert everything to numbers so it's fast
10262 var day = 86400000;
10263 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
10266 //Roo.log(prevStart);
10268 var today = new Date().clearTime().getTime();
10269 var sel = date.clearTime().getTime();
10270 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
10271 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
10272 var ddMatch = this.disabledDatesRE;
10273 var ddText = this.disabledDatesText;
10274 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
10275 var ddaysText = this.disabledDaysText;
10276 var format = this.format;
10278 var setCellClass = function(cal, cell){
10280 //Roo.log('set Cell Class');
10282 var t = d.getTime();
10286 cell.dateValue = t;
10288 cell.className += " fc-today";
10289 cell.className += " fc-state-highlight";
10290 cell.title = cal.todayText;
10293 // disable highlight in other month..
10294 //cell.className += " fc-state-highlight";
10299 cell.className = " fc-state-disabled";
10300 cell.title = cal.minText;
10304 cell.className = " fc-state-disabled";
10305 cell.title = cal.maxText;
10309 if(ddays.indexOf(d.getDay()) != -1){
10310 cell.title = ddaysText;
10311 cell.className = " fc-state-disabled";
10314 if(ddMatch && format){
10315 var fvalue = d.dateFormat(format);
10316 if(ddMatch.test(fvalue)){
10317 cell.title = ddText.replace("%0", fvalue);
10318 cell.className = " fc-state-disabled";
10322 if (!cell.initialClassName) {
10323 cell.initialClassName = cell.dom.className;
10326 cell.dom.className = cell.initialClassName + ' ' + cell.className;
10331 for(; i < startingPos; i++) {
10332 textEls[i].innerHTML = (++prevStart);
10333 d.setDate(d.getDate()+1);
10335 cells[i].className = "fc-past fc-other-month";
10336 setCellClass(this, cells[i]);
10341 for(; i < days; i++){
10342 intDay = i - startingPos + 1;
10343 textEls[i].innerHTML = (intDay);
10344 d.setDate(d.getDate()+1);
10346 cells[i].className = ''; // "x-date-active";
10347 setCellClass(this, cells[i]);
10351 for(; i < 42; i++) {
10352 textEls[i].innerHTML = (++extraDays);
10353 d.setDate(d.getDate()+1);
10355 cells[i].className = "fc-future fc-other-month";
10356 setCellClass(this, cells[i]);
10359 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
10361 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
10363 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
10364 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
10366 if(totalRows != 6){
10367 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
10368 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
10371 this.fireEvent('monthchange', this, date);
10375 if(!this.internalRender){
10376 var main = this.el.dom.firstChild;
10377 var w = main.offsetWidth;
10378 this.el.setWidth(w + this.el.getBorderWidth("lr"));
10379 Roo.fly(main).setWidth(w);
10380 this.internalRender = true;
10381 // opera does not respect the auto grow header center column
10382 // then, after it gets a width opera refuses to recalculate
10383 // without a second pass
10384 if(Roo.isOpera && !this.secondPass){
10385 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
10386 this.secondPass = true;
10387 this.update.defer(10, this, [date]);
10394 findCell : function(dt) {
10395 dt = dt.clearTime().getTime();
10397 this.cells.each(function(c){
10398 //Roo.log("check " +c.dateValue + '?=' + dt);
10399 if(c.dateValue == dt){
10409 findCells : function(ev) {
10410 var s = ev.start.clone().clearTime().getTime();
10412 var e= ev.end.clone().clearTime().getTime();
10415 this.cells.each(function(c){
10416 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
10418 if(c.dateValue > e){
10421 if(c.dateValue < s){
10430 findBestRow: function(cells)
10434 for (var i =0 ; i < cells.length;i++) {
10435 ret = Math.max(cells[i].rows || 0,ret);
10442 addItem : function(ev)
10444 // look for vertical location slot in
10445 var cells = this.findCells(ev);
10447 ev.row = this.findBestRow(cells);
10449 // work out the location.
10453 for(var i =0; i < cells.length; i++) {
10461 if (crow.start.getY() == cells[i].getY()) {
10463 crow.end = cells[i];
10479 for (var i = 0; i < cells.length;i++) {
10480 cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
10484 this.calevents.push(ev);
10487 clearEvents: function() {
10489 if(!this.calevents){
10493 Roo.each(this.cells.elements, function(c){
10497 Roo.each(this.calevents, function(e) {
10498 Roo.each(e.els, function(el) {
10499 el.un('mouseenter' ,this.onEventEnter, this);
10500 el.un('mouseleave' ,this.onEventLeave, this);
10507 renderEvents: function()
10509 // first make sure there is enough space..
10511 this.cells.each(function(c) {
10513 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.rows * 20));
10516 for (var e = 0; e < this.calevents.length; e++) {
10517 var ev = this.calevents[e];
10518 var cells = ev.cells;
10519 var rows = ev.rows;
10521 for(var i =0; i < rows.length; i++) {
10524 // how many rows should it span..
10527 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
10528 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
10530 unselectable : "on",
10533 cls: 'fc-event-inner',
10537 // cls: 'fc-event-time',
10538 // html : cells.length > 1 ? '' : ev.time
10542 cls: 'fc-event-title',
10543 html : String.format('{0}', ev.title)
10550 cls: 'ui-resizable-handle ui-resizable-e',
10551 html : '  '
10557 cfg.cls += ' fc-event-start';
10559 if ((i+1) == rows.length) {
10560 cfg.cls += ' fc-event-end';
10563 var ctr = this.el.select('.fc-event-container',true).first();
10564 var cg = ctr.createChild(cfg);
10566 cg.on('mouseenter' ,this.onEventEnter, this, ev);
10567 cg.on('mouseleave' ,this.onEventLeave, this, ev);
10568 cg.on('click', this.onEventClick, this, ev);
10572 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
10573 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
10575 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
10576 cg.setWidth(ebox.right - sbox.x -2);
10584 onEventEnter: function (e, el,event,d) {
10585 this.fireEvent('evententer', this, el, event);
10588 onEventLeave: function (e, el,event,d) {
10589 this.fireEvent('eventleave', this, el, event);
10592 onEventClick: function (e, el,event,d) {
10593 this.fireEvent('eventclick', this, el, event);
10596 onMonthChange: function () {
10600 onLoad: function ()
10602 this.calevents = [];
10605 if(this.store.getCount() > 0){
10606 this.store.data.each(function(d){
10609 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
10610 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
10611 time : d.data.start_time,
10612 title : d.data.title,
10613 description : d.data.description,
10614 venue : d.data.venue
10619 this.renderEvents();
10622 this.maskEl.hide();
10626 onBeforeLoad: function()
10628 this.clearEvents();
10631 this.maskEl.show();
10645 * @class Roo.bootstrap.Popover
10646 * @extends Roo.bootstrap.Component
10647 * Bootstrap Popover class
10648 * @cfg {String} html contents of the popover (or false to use children..)
10649 * @cfg {String} title of popover (or false to hide)
10650 * @cfg {String} placement how it is placed
10651 * @cfg {String} trigger click || hover (or false to trigger manually)
10652 * @cfg {String} over what (parent or false to trigger manually.)
10655 * Create a new Popover
10656 * @param {Object} config The config object
10659 Roo.bootstrap.Popover = function(config){
10660 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
10663 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
10665 title: 'Fill in a title',
10668 placement : 'right',
10669 trigger : 'hover', // hover
10673 can_build_overlaid : false,
10675 getChildContainer : function()
10677 return this.el.select('.popover-content',true).first();
10680 getAutoCreate : function(){
10681 Roo.log('make popover?');
10683 cls : 'popover roo-dynamic',
10684 style: 'display:block',
10690 cls : 'popover-inner',
10694 cls: 'popover-title',
10698 cls : 'popover-content',
10709 setTitle: function(str)
10711 this.el.select('.popover-title',true).first().dom.innerHTML = str;
10713 setContent: function(str)
10715 this.el.select('.popover-content',true).first().dom.innerHTML = str;
10717 // as it get's added to the bottom of the page.
10718 onRender : function(ct, position)
10720 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
10722 var cfg = Roo.apply({}, this.getAutoCreate());
10726 cfg.cls += ' ' + this.cls;
10729 cfg.style = this.style;
10731 Roo.log("adding to ")
10732 this.el = Roo.get(document.body).createChild(cfg, position);
10738 initEvents : function()
10740 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
10741 this.el.enableDisplayMode('block');
10743 if (this.over === false) {
10746 if (this.triggers === false) {
10749 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
10750 var triggers = this.trigger ? this.trigger.split(' ') : [];
10751 Roo.each(triggers, function(trigger) {
10753 if (trigger == 'click') {
10754 on_el.on('click', this.toggle, this);
10755 } else if (trigger != 'manual') {
10756 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
10757 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
10759 on_el.on(eventIn ,this.enter, this);
10760 on_el.on(eventOut, this.leave, this);
10771 toggle : function () {
10772 this.hoverState == 'in' ? this.leave() : this.enter();
10775 enter : function () {
10778 clearTimeout(this.timeout);
10780 this.hoverState = 'in'
10782 if (!this.delay || !this.delay.show) {
10787 this.timeout = setTimeout(function () {
10788 if (_t.hoverState == 'in') {
10791 }, this.delay.show)
10793 leave : function() {
10794 clearTimeout(this.timeout);
10796 this.hoverState = 'out'
10798 if (!this.delay || !this.delay.hide) {
10803 this.timeout = setTimeout(function () {
10804 if (_t.hoverState == 'out') {
10807 }, this.delay.hide)
10810 show : function (on_el)
10813 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
10816 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
10817 if (this.html !== false) {
10818 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
10820 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
10821 if (!this.title.length) {
10822 this.el.select('.popover-title',true).hide();
10825 var placement = typeof this.placement == 'function' ?
10826 this.placement.call(this, this.el, on_el) :
10829 var autoToken = /\s?auto?\s?/i;
10830 var autoPlace = autoToken.test(placement);
10832 placement = placement.replace(autoToken, '') || 'top';
10836 //this.el.setXY([0,0]);
10838 this.el.dom.style.display='block';
10839 this.el.addClass(placement);
10841 //this.el.appendTo(on_el);
10843 var p = this.getPosition();
10844 var box = this.el.getBox();
10849 var align = Roo.bootstrap.Popover.alignment[placement]
10850 this.el.alignTo(on_el, align[0],align[1]);
10851 //var arrow = this.el.select('.arrow',true).first();
10852 //arrow.set(align[2],
10854 this.el.addClass('in');
10855 this.hoverState = null;
10857 if (this.el.hasClass('fade')) {
10864 this.el.setXY([0,0]);
10865 this.el.removeClass('in');
10872 Roo.bootstrap.Popover.alignment = {
10873 'left' : ['r-l', [-10,0], 'right'],
10874 'right' : ['l-r', [10,0], 'left'],
10875 'bottom' : ['t-b', [0,10], 'top'],
10876 'top' : [ 'b-t', [0,-10], 'bottom']
10887 * @class Roo.bootstrap.Progress
10888 * @extends Roo.bootstrap.Component
10889 * Bootstrap Progress class
10890 * @cfg {Boolean} striped striped of the progress bar
10891 * @cfg {Boolean} active animated of the progress bar
10895 * Create a new Progress
10896 * @param {Object} config The config object
10899 Roo.bootstrap.Progress = function(config){
10900 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
10903 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
10908 getAutoCreate : function(){
10916 cfg.cls += ' progress-striped';
10920 cfg.cls += ' active';
10939 * @class Roo.bootstrap.ProgressBar
10940 * @extends Roo.bootstrap.Component
10941 * Bootstrap ProgressBar class
10942 * @cfg {Number} aria_valuenow aria-value now
10943 * @cfg {Number} aria_valuemin aria-value min
10944 * @cfg {Number} aria_valuemax aria-value max
10945 * @cfg {String} label label for the progress bar
10946 * @cfg {String} panel (success | info | warning | danger )
10947 * @cfg {String} role role of the progress bar
10948 * @cfg {String} sr_only text
10952 * Create a new ProgressBar
10953 * @param {Object} config The config object
10956 Roo.bootstrap.ProgressBar = function(config){
10957 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
10960 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
10964 aria_valuemax : 100,
10970 getAutoCreate : function()
10975 cls: 'progress-bar',
10976 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
10988 cfg.role = this.role;
10991 if(this.aria_valuenow){
10992 cfg['aria-valuenow'] = this.aria_valuenow;
10995 if(this.aria_valuemin){
10996 cfg['aria-valuemin'] = this.aria_valuemin;
10999 if(this.aria_valuemax){
11000 cfg['aria-valuemax'] = this.aria_valuemax;
11003 if(this.label && !this.sr_only){
11004 cfg.html = this.label;
11008 cfg.cls += ' progress-bar-' + this.panel;
11014 update : function(aria_valuenow)
11016 this.aria_valuenow = aria_valuenow;
11018 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
11033 * @class Roo.bootstrap.TabPanel
11034 * @extends Roo.bootstrap.Component
11035 * Bootstrap TabPanel class
11036 * @cfg {Boolean} active panel active
11037 * @cfg {String} html panel content
11038 * @cfg {String} tabId tab relate id
11039 * @cfg {String} navId The navbar which triggers show hide
11043 * Create a new TabPanel
11044 * @param {Object} config The config object
11047 Roo.bootstrap.TabPanel = function(config){
11048 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
11051 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
11058 getAutoCreate : function(){
11062 html: this.html || ''
11066 cfg.cls += ' active';
11070 cfg.tabId = this.tabId;
11075 onRender : function(ct, position)
11077 // Roo.log("Call onRender: " + this.xtype);
11079 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
11081 if (this.navId && this.tabId) {
11082 var item = Roo.bootstrap.NavGroup.get(this.navId).getNavItem(this.tabId);
11084 Roo.log("could not find navID:" + this.navId + ", tabId: " + this.tabId);
11086 item.on('changed', function(item, state) {
11087 this.setActive(state);
11093 setActive: function(state)
11095 Roo.log("panel - set active " + this.tabId + "=" + state);
11097 this.active = state;
11099 this.el.removeClass('active');
11101 } else if (!this.el.hasClass('active')) {
11102 this.el.addClass('active');
11104 this.fireEvent('changed', this, state);
11121 * @class Roo.bootstrap.DateField
11122 * @extends Roo.bootstrap.Input
11123 * Bootstrap DateField class
11124 * @cfg {Number} weekStart default 0
11125 * @cfg {Number} weekStart default 0
11126 * @cfg {Number} viewMode default empty, (months|years)
11127 * @cfg {Number} minViewMode default empty, (months|years)
11128 * @cfg {Number} startDate default -Infinity
11129 * @cfg {Number} endDate default Infinity
11130 * @cfg {Boolean} todayHighlight default false
11131 * @cfg {Boolean} todayBtn default false
11132 * @cfg {Boolean} calendarWeeks default false
11133 * @cfg {Object} daysOfWeekDisabled default empty
11135 * @cfg {Boolean} keyboardNavigation default true
11136 * @cfg {String} language default en
11139 * Create a new DateField
11140 * @param {Object} config The config object
11143 Roo.bootstrap.DateField = function(config){
11144 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
11148 * Fires when this field show.
11149 * @param {Roo.bootstrap.DateField} this
11150 * @param {Mixed} date The date value
11155 * Fires when this field hide.
11156 * @param {Roo.bootstrap.DateField} this
11157 * @param {Mixed} date The date value
11162 * Fires when select a date.
11163 * @param {Roo.bootstrap.DateField} this
11164 * @param {Mixed} date The date value
11170 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
11173 * @cfg {String} format
11174 * The default date format string which can be overriden for localization support. The format must be
11175 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
11179 * @cfg {String} altFormats
11180 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
11181 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
11183 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
11191 todayHighlight : false,
11197 keyboardNavigation: true,
11199 calendarWeeks: false,
11201 startDate: -Infinity,
11205 daysOfWeekDisabled: [],
11209 UTCDate: function()
11211 return new Date(Date.UTC.apply(Date, arguments));
11214 UTCToday: function()
11216 var today = new Date();
11217 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
11220 getDate: function() {
11221 var d = this.getUTCDate();
11222 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
11225 getUTCDate: function() {
11229 setDate: function(d) {
11230 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
11233 setUTCDate: function(d) {
11235 this.setValue(this.formatDate(this.date));
11238 onRender: function(ct, position)
11241 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
11243 this.language = this.language || 'en';
11244 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
11245 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
11247 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
11248 this.format = this.format || 'm/d/y';
11249 this.isInline = false;
11250 this.isInput = true;
11251 this.component = this.el.select('.add-on', true).first() || false;
11252 this.component = (this.component && this.component.length === 0) ? false : this.component;
11253 this.hasInput = this.component && this.inputEL().length;
11255 if (typeof(this.minViewMode === 'string')) {
11256 switch (this.minViewMode) {
11258 this.minViewMode = 1;
11261 this.minViewMode = 2;
11264 this.minViewMode = 0;
11269 if (typeof(this.viewMode === 'string')) {
11270 switch (this.viewMode) {
11283 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
11285 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
11287 this.picker().on('mousedown', this.onMousedown, this);
11288 this.picker().on('click', this.onClick, this);
11290 this.picker().addClass('datepicker-dropdown');
11292 this.startViewMode = this.viewMode;
11295 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
11296 if(!this.calendarWeeks){
11301 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
11302 v.attr('colspan', function(i, val){
11303 return parseInt(val) + 1;
11308 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
11310 this.setStartDate(this.startDate);
11311 this.setEndDate(this.endDate);
11313 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
11320 if(this.isInline) {
11325 picker : function()
11327 return this.el.select('.datepicker', true).first();
11330 fillDow: function()
11332 var dowCnt = this.weekStart;
11341 if(this.calendarWeeks){
11349 while (dowCnt < this.weekStart + 7) {
11353 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
11357 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
11360 fillMonths: function()
11363 var months = this.picker().select('>.datepicker-months td', true).first();
11365 months.dom.innerHTML = '';
11371 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
11374 months.createChild(month);
11379 update: function(){
11381 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
11383 if (this.date < this.startDate) {
11384 this.viewDate = new Date(this.startDate);
11385 } else if (this.date > this.endDate) {
11386 this.viewDate = new Date(this.endDate);
11388 this.viewDate = new Date(this.date);
11395 var d = new Date(this.viewDate),
11396 year = d.getUTCFullYear(),
11397 month = d.getUTCMonth(),
11398 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
11399 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
11400 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
11401 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
11402 currentDate = this.date && this.date.valueOf(),
11403 today = this.UTCToday();
11405 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
11407 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
11409 // this.picker.select('>tfoot th.today').
11410 // .text(dates[this.language].today)
11411 // .toggle(this.todayBtn !== false);
11413 this.updateNavArrows();
11416 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
11418 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
11420 prevMonth.setUTCDate(day);
11422 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
11424 var nextMonth = new Date(prevMonth);
11426 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
11428 nextMonth = nextMonth.valueOf();
11430 var fillMonths = false;
11432 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
11434 while(prevMonth.valueOf() < nextMonth) {
11437 if (prevMonth.getUTCDay() === this.weekStart) {
11439 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
11447 if(this.calendarWeeks){
11448 // ISO 8601: First week contains first thursday.
11449 // ISO also states week starts on Monday, but we can be more abstract here.
11451 // Start of current week: based on weekstart/current date
11452 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
11453 // Thursday of this week
11454 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
11455 // First Thursday of year, year from thursday
11456 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
11457 // Calendar week: ms between thursdays, div ms per day, div 7 days
11458 calWeek = (th - yth) / 864e5 / 7 + 1;
11460 fillMonths.cn.push({
11468 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
11470 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
11473 if (this.todayHighlight &&
11474 prevMonth.getUTCFullYear() == today.getFullYear() &&
11475 prevMonth.getUTCMonth() == today.getMonth() &&
11476 prevMonth.getUTCDate() == today.getDate()) {
11477 clsName += ' today';
11480 if (currentDate && prevMonth.valueOf() === currentDate) {
11481 clsName += ' active';
11484 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
11485 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
11486 clsName += ' disabled';
11489 fillMonths.cn.push({
11491 cls: 'day ' + clsName,
11492 html: prevMonth.getDate()
11495 prevMonth.setDate(prevMonth.getDate()+1);
11498 var currentYear = this.date && this.date.getUTCFullYear();
11499 var currentMonth = this.date && this.date.getUTCMonth();
11501 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
11503 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
11504 v.removeClass('active');
11506 if(currentYear === year && k === currentMonth){
11507 v.addClass('active');
11510 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
11511 v.addClass('disabled');
11517 year = parseInt(year/10, 10) * 10;
11519 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
11521 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
11524 for (var i = -1; i < 11; i++) {
11525 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
11527 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
11535 showMode: function(dir) {
11537 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
11539 Roo.each(this.picker().select('>div',true).elements, function(v){
11540 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
11543 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
11548 if(this.isInline) return;
11550 this.picker().removeClass(['bottom', 'top']);
11552 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
11554 * place to the top of element!
11558 this.picker().addClass('top');
11559 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
11564 this.picker().addClass('bottom');
11566 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
11569 parseDate : function(value){
11570 if(!value || value instanceof Date){
11573 var v = Date.parseDate(value, this.format);
11574 if (!v && this.useIso) {
11575 v = Date.parseDate(value, 'Y-m-d');
11577 if(!v && this.altFormats){
11578 if(!this.altFormatsArray){
11579 this.altFormatsArray = this.altFormats.split("|");
11581 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
11582 v = Date.parseDate(value, this.altFormatsArray[i]);
11588 formatDate : function(date, fmt){
11589 return (!date || !(date instanceof Date)) ?
11590 date : date.dateFormat(fmt || this.format);
11593 onFocus : function()
11595 Roo.bootstrap.DateField.superclass.onFocus.call(this);
11599 onBlur : function()
11601 Roo.bootstrap.DateField.superclass.onBlur.call(this);
11607 this.picker().show();
11611 this.fireEvent('show', this, this.date);
11616 if(this.isInline) return;
11617 this.picker().hide();
11618 this.viewMode = this.startViewMode;
11621 this.fireEvent('hide', this, this.date);
11625 onMousedown: function(e){
11626 e.stopPropagation();
11627 e.preventDefault();
11630 keyup: function(e){
11631 Roo.bootstrap.DateField.superclass.keyup.call(this);
11636 setValue: function(v){
11637 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
11639 this.fireEvent('select', this, this.date);
11643 fireKey: function(e){
11644 if (!this.picker().isVisible()){
11645 if (e.keyCode == 27) // allow escape to hide and re-show picker
11649 var dateChanged = false,
11651 newDate, newViewDate;
11655 e.preventDefault();
11659 if (!this.keyboardNavigation) break;
11660 dir = e.keyCode == 37 ? -1 : 1;
11663 newDate = this.moveYear(this.date, dir);
11664 newViewDate = this.moveYear(this.viewDate, dir);
11665 } else if (e.shiftKey){
11666 newDate = this.moveMonth(this.date, dir);
11667 newViewDate = this.moveMonth(this.viewDate, dir);
11669 newDate = new Date(this.date);
11670 newDate.setUTCDate(this.date.getUTCDate() + dir);
11671 newViewDate = new Date(this.viewDate);
11672 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
11674 if (this.dateWithinRange(newDate)){
11675 this.date = newDate;
11676 this.viewDate = newViewDate;
11677 this.setValue(this.formatDate(this.date));
11679 e.preventDefault();
11680 dateChanged = true;
11685 if (!this.keyboardNavigation) break;
11686 dir = e.keyCode == 38 ? -1 : 1;
11688 newDate = this.moveYear(this.date, dir);
11689 newViewDate = this.moveYear(this.viewDate, dir);
11690 } else if (e.shiftKey){
11691 newDate = this.moveMonth(this.date, dir);
11692 newViewDate = this.moveMonth(this.viewDate, dir);
11694 newDate = new Date(this.date);
11695 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
11696 newViewDate = new Date(this.viewDate);
11697 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
11699 if (this.dateWithinRange(newDate)){
11700 this.date = newDate;
11701 this.viewDate = newViewDate;
11702 this.setValue(this.formatDate(this.date));
11704 e.preventDefault();
11705 dateChanged = true;
11709 this.setValue(this.formatDate(this.date));
11711 e.preventDefault();
11714 this.setValue(this.formatDate(this.date));
11721 onClick: function(e) {
11722 e.stopPropagation();
11723 e.preventDefault();
11725 var target = e.getTarget();
11727 if(target.nodeName.toLowerCase() === 'i'){
11728 target = Roo.get(target).dom.parentNode;
11731 var nodeName = target.nodeName;
11732 var className = target.className;
11733 var html = target.innerHTML;
11735 switch(nodeName.toLowerCase()) {
11737 switch(className) {
11743 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
11744 switch(this.viewMode){
11746 this.viewDate = this.moveMonth(this.viewDate, dir);
11750 this.viewDate = this.moveYear(this.viewDate, dir);
11756 var date = new Date();
11757 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
11759 this.setValue(this.formatDate(this.date));
11765 if (className.indexOf('disabled') === -1) {
11766 this.viewDate.setUTCDate(1);
11767 if (className.indexOf('month') !== -1) {
11768 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
11770 var year = parseInt(html, 10) || 0;
11771 this.viewDate.setUTCFullYear(year);
11780 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
11781 var day = parseInt(html, 10) || 1;
11782 var year = this.viewDate.getUTCFullYear(),
11783 month = this.viewDate.getUTCMonth();
11785 if (className.indexOf('old') !== -1) {
11792 } else if (className.indexOf('new') !== -1) {
11800 this.date = this.UTCDate(year, month, day,0,0,0,0);
11801 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
11803 this.setValue(this.formatDate(this.date));
11810 setStartDate: function(startDate){
11811 this.startDate = startDate || -Infinity;
11812 if (this.startDate !== -Infinity) {
11813 this.startDate = this.parseDate(this.startDate);
11816 this.updateNavArrows();
11819 setEndDate: function(endDate){
11820 this.endDate = endDate || Infinity;
11821 if (this.endDate !== Infinity) {
11822 this.endDate = this.parseDate(this.endDate);
11825 this.updateNavArrows();
11828 setDaysOfWeekDisabled: function(daysOfWeekDisabled){
11829 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
11830 if (typeof(this.daysOfWeekDisabled) !== 'object') {
11831 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
11833 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
11834 return parseInt(d, 10);
11837 this.updateNavArrows();
11840 updateNavArrows: function() {
11841 var d = new Date(this.viewDate),
11842 year = d.getUTCFullYear(),
11843 month = d.getUTCMonth();
11845 Roo.each(this.picker().select('.prev', true).elements, function(v){
11847 switch (this.viewMode) {
11850 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
11856 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
11863 Roo.each(this.picker().select('.next', true).elements, function(v){
11865 switch (this.viewMode) {
11868 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
11874 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
11882 moveMonth: function(date, dir){
11883 if (!dir) return date;
11884 var new_date = new Date(date.valueOf()),
11885 day = new_date.getUTCDate(),
11886 month = new_date.getUTCMonth(),
11887 mag = Math.abs(dir),
11889 dir = dir > 0 ? 1 : -1;
11892 // If going back one month, make sure month is not current month
11893 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
11895 return new_date.getUTCMonth() == month;
11897 // If going forward one month, make sure month is as expected
11898 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
11900 return new_date.getUTCMonth() != new_month;
11902 new_month = month + dir;
11903 new_date.setUTCMonth(new_month);
11904 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
11905 if (new_month < 0 || new_month > 11)
11906 new_month = (new_month + 12) % 12;
11908 // For magnitudes >1, move one month at a time...
11909 for (var i=0; i<mag; i++)
11910 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
11911 new_date = this.moveMonth(new_date, dir);
11912 // ...then reset the day, keeping it in the new month
11913 new_month = new_date.getUTCMonth();
11914 new_date.setUTCDate(day);
11916 return new_month != new_date.getUTCMonth();
11919 // Common date-resetting loop -- if date is beyond end of month, make it
11922 new_date.setUTCDate(--day);
11923 new_date.setUTCMonth(new_month);
11928 moveYear: function(date, dir){
11929 return this.moveMonth(date, dir*12);
11932 dateWithinRange: function(date){
11933 return date >= this.startDate && date <= this.endDate;
11937 remove: function() {
11938 this.picker().remove();
11943 Roo.apply(Roo.bootstrap.DateField, {
11954 html: '<i class="icon-arrow-left"/>'
11964 html: '<i class="icon-arrow-right"/>'
12006 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
12007 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
12008 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
12009 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
12010 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
12023 navFnc: 'FullYear',
12028 navFnc: 'FullYear',
12033 Roo.apply(Roo.bootstrap.DateField, {
12037 cls: 'datepicker dropdown-menu',
12041 cls: 'datepicker-days',
12045 cls: 'table-condensed',
12047 Roo.bootstrap.DateField.head,
12051 Roo.bootstrap.DateField.footer
12058 cls: 'datepicker-months',
12062 cls: 'table-condensed',
12064 Roo.bootstrap.DateField.head,
12065 Roo.bootstrap.DateField.content,
12066 Roo.bootstrap.DateField.footer
12073 cls: 'datepicker-years',
12077 cls: 'table-condensed',
12079 Roo.bootstrap.DateField.head,
12080 Roo.bootstrap.DateField.content,
12081 Roo.bootstrap.DateField.footer
12100 * @class Roo.bootstrap.TimeField
12101 * @extends Roo.bootstrap.Input
12102 * Bootstrap DateField class
12106 * Create a new TimeField
12107 * @param {Object} config The config object
12110 Roo.bootstrap.TimeField = function(config){
12111 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
12115 * Fires when this field show.
12116 * @param {Roo.bootstrap.DateField} this
12117 * @param {Mixed} date The date value
12122 * Fires when this field hide.
12123 * @param {Roo.bootstrap.DateField} this
12124 * @param {Mixed} date The date value
12129 * Fires when select a date.
12130 * @param {Roo.bootstrap.DateField} this
12131 * @param {Mixed} date The date value
12137 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
12140 * @cfg {String} format
12141 * The default time format string which can be overriden for localization support. The format must be
12142 * valid according to {@link Date#parseDate} (defaults to 'H:i').
12146 onRender: function(ct, position)
12149 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
12151 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
12153 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12155 this.pop = this.picker().select('>.datepicker-time',true).first();
12156 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
12158 this.picker().on('mousedown', this.onMousedown, this);
12159 this.picker().on('click', this.onClick, this);
12161 this.picker().addClass('datepicker-dropdown');
12166 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
12167 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
12168 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
12169 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
12170 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
12171 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
12175 fireKey: function(e){
12176 if (!this.picker().isVisible()){
12177 if (e.keyCode == 27) // allow escape to hide and re-show picker
12182 e.preventDefault();
12190 this.onTogglePeriod();
12193 this.onIncrementMinutes();
12196 this.onDecrementMinutes();
12205 onClick: function(e) {
12206 e.stopPropagation();
12207 e.preventDefault();
12210 picker : function()
12212 return this.el.select('.datepicker', true).first();
12215 fillTime: function()
12217 var time = this.pop.select('tbody', true).first();
12219 time.dom.innerHTML = '';
12234 cls: 'hours-up glyphicon glyphicon-chevron-up'
12254 cls: 'minutes-up glyphicon glyphicon-chevron-up'
12275 cls: 'timepicker-hour',
12290 cls: 'timepicker-minute',
12305 cls: 'btn btn-primary period',
12327 cls: 'hours-down glyphicon glyphicon-chevron-down'
12347 cls: 'minutes-down glyphicon glyphicon-chevron-down'
12365 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
12372 var hours = this.time.getHours();
12373 var minutes = this.time.getMinutes();
12386 hours = hours - 12;
12390 hours = '0' + hours;
12394 minutes = '0' + minutes;
12397 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
12398 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
12399 this.pop.select('button', true).first().dom.innerHTML = period;
12405 this.picker().removeClass(['bottom', 'top']);
12407 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
12409 * place to the top of element!
12413 this.picker().addClass('top');
12414 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12419 this.picker().addClass('bottom');
12421 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12424 onFocus : function()
12426 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
12430 onBlur : function()
12432 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
12438 this.picker().show();
12443 this.fireEvent('show', this, this.date);
12448 this.picker().hide();
12451 this.fireEvent('hide', this, this.date);
12454 setTime : function()
12457 this.setValue(this.time.format(this.format));
12459 this.fireEvent('select', this, this.date);
12464 onMousedown: function(e){
12465 e.stopPropagation();
12466 e.preventDefault();
12469 onIncrementHours: function()
12471 Roo.log('onIncrementHours');
12472 this.time = this.time.add(Date.HOUR, 1);
12477 onDecrementHours: function()
12479 Roo.log('onDecrementHours');
12480 this.time = this.time.add(Date.HOUR, -1);
12484 onIncrementMinutes: function()
12486 Roo.log('onIncrementMinutes');
12487 this.time = this.time.add(Date.MINUTE, 1);
12491 onDecrementMinutes: function()
12493 Roo.log('onDecrementMinutes');
12494 this.time = this.time.add(Date.MINUTE, -1);
12498 onTogglePeriod: function()
12500 Roo.log('onTogglePeriod');
12501 this.time = this.time.add(Date.HOUR, 12);
12508 Roo.apply(Roo.bootstrap.TimeField, {
12538 cls: 'btn btn-info ok',
12550 Roo.apply(Roo.bootstrap.TimeField, {
12554 cls: 'datepicker dropdown-menu',
12558 cls: 'datepicker-time',
12562 cls: 'table-condensed',
12564 Roo.bootstrap.TimeField.content,
12565 Roo.bootstrap.TimeField.footer
12584 * @class Roo.bootstrap.CheckBox
12585 * @extends Roo.bootstrap.Input
12586 * Bootstrap CheckBox class
12588 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
12589 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
12590 * @cfg {String} boxLabel The text that appears beside the checkbox
12591 * @cfg {Boolean} checked initnal the element
12594 * Create a new CheckBox
12595 * @param {Object} config The config object
12598 Roo.bootstrap.CheckBox = function(config){
12599 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
12604 * Fires when the element is checked or unchecked.
12605 * @param {Roo.bootstrap.CheckBox} this This input
12606 * @param {Boolean} checked The new checked value
12612 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
12614 inputType: 'checkbox',
12620 getAutoCreate : function()
12622 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
12628 cfg.cls = 'form-group' //input-group
12633 type : this.inputType,
12634 value : (!this.checked) ? this.valueOff : this.inputValue,
12636 placeholder : this.placeholder || ''
12640 if (this.disabled) {
12641 input.disabled=true;
12645 input.checked = this.checked;
12649 input.name = this.name;
12653 input.cls += ' input-' + this.size;
12657 ['xs','sm','md','lg'].map(function(size){
12658 if (settings[size]) {
12659 cfg.cls += ' col-' + size + '-' + settings[size];
12663 var inputblock = input;
12665 if (this.before || this.after) {
12668 cls : 'input-group',
12672 inputblock.cn.push({
12674 cls : 'input-group-addon',
12678 inputblock.cn.push(input);
12680 inputblock.cn.push({
12682 cls : 'input-group-addon',
12689 if (align ==='left' && this.fieldLabel.length) {
12690 Roo.log("left and has label");
12696 cls : 'control-label col-md-' + this.labelWidth,
12697 html : this.fieldLabel
12701 cls : "col-md-" + (12 - this.labelWidth),
12708 } else if ( this.fieldLabel.length) {
12713 tag: this.boxLabel ? 'span' : 'label',
12715 cls: 'control-label box-input-label',
12716 //cls : 'input-group-addon',
12717 html : this.fieldLabel
12727 Roo.log(" no label && no align");
12742 html: this.boxLabel
12751 * return the real input element.
12753 inputEl: function ()
12755 return this.el.select('input.form-box',true).first();
12758 initEvents : function()
12760 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
12762 this.inputEl().on('click', this.onClick, this);
12766 onClick : function()
12768 this.setChecked(!this.checked);
12771 setChecked : function(state,suppressEvent)
12773 this.checked = state;
12775 this.inputEl().dom.checked = state;
12777 if(suppressEvent !== true){
12778 this.fireEvent('check', this, state);
12781 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
12785 setValue : function(v,suppressEvent)
12787 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
12801 * @class Roo.bootstrap.Radio
12802 * @extends Roo.bootstrap.CheckBox
12803 * Bootstrap Radio class
12806 * Create a new Radio
12807 * @param {Object} config The config object
12810 Roo.bootstrap.Radio = function(config){
12811 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
12815 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
12817 inputType: 'radio',
12821 getAutoCreate : function()
12823 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
12829 cfg.cls = 'form-group' //input-group
12834 type : this.inputType,
12835 value : (!this.checked) ? this.valueOff : this.inputValue,
12837 placeholder : this.placeholder || ''
12841 if (this.disabled) {
12842 input.disabled=true;
12846 input.checked = this.checked;
12850 input.name = this.name;
12854 input.cls += ' input-' + this.size;
12858 ['xs','sm','md','lg'].map(function(size){
12859 if (settings[size]) {
12860 cfg.cls += ' col-' + size + '-' + settings[size];
12864 var inputblock = input;
12866 if (this.before || this.after) {
12869 cls : 'input-group',
12873 inputblock.cn.push({
12875 cls : 'input-group-addon',
12879 inputblock.cn.push(input);
12881 inputblock.cn.push({
12883 cls : 'input-group-addon',
12890 if (align ==='left' && this.fieldLabel.length) {
12891 Roo.log("left and has label");
12897 cls : 'control-label col-md-' + this.labelWidth,
12898 html : this.fieldLabel
12902 cls : "col-md-" + (12 - this.labelWidth),
12909 } else if ( this.fieldLabel.length) {
12916 cls: 'control-label box-input-label',
12917 //cls : 'input-group-addon',
12918 html : this.fieldLabel
12928 Roo.log(" no label && no align");
12943 html: this.boxLabel
12951 onClick : function()
12953 this.setChecked(true);
12956 setChecked : function(state,suppressEvent)
12959 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
12960 v.dom.checked = false;
12964 this.checked = state;
12965 this.inputEl().dom.checked = state;
12967 if(suppressEvent !== true){
12968 this.fireEvent('check', this, state);
12971 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
12975 getGroupValue : function()
12978 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
12979 if(v.dom.checked == true){
12980 value = v.dom.value;
12988 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
12989 * @return {Mixed} value The field value
12991 getValue : function(){
12992 return this.getGroupValue();
12998 //<script type="text/javascript">
13001 * Based Ext JS Library 1.1.1
13002 * Copyright(c) 2006-2007, Ext JS, LLC.
13008 * @class Roo.HtmlEditorCore
13009 * @extends Roo.Component
13010 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
13012 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
13015 Roo.HtmlEditorCore = function(config){
13018 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
13021 * @event initialize
13022 * Fires when the editor is fully initialized (including the iframe)
13023 * @param {Roo.HtmlEditorCore} this
13028 * Fires when the editor is first receives the focus. Any insertion must wait
13029 * until after this event.
13030 * @param {Roo.HtmlEditorCore} this
13034 * @event beforesync
13035 * Fires before the textarea is updated with content from the editor iframe. Return false
13036 * to cancel the sync.
13037 * @param {Roo.HtmlEditorCore} this
13038 * @param {String} html
13042 * @event beforepush
13043 * Fires before the iframe editor is updated with content from the textarea. Return false
13044 * to cancel the push.
13045 * @param {Roo.HtmlEditorCore} this
13046 * @param {String} html
13051 * Fires when the textarea is updated with content from the editor iframe.
13052 * @param {Roo.HtmlEditorCore} this
13053 * @param {String} html
13058 * Fires when the iframe editor is updated with content from the textarea.
13059 * @param {Roo.HtmlEditorCore} this
13060 * @param {String} html
13065 * @event editorevent
13066 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
13067 * @param {Roo.HtmlEditorCore} this
13075 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
13079 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
13085 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
13090 * @cfg {Number} height (in pixels)
13094 * @cfg {Number} width (in pixels)
13099 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
13102 stylesheets: false,
13107 // private properties
13108 validationEvent : false,
13110 initialized : false,
13112 sourceEditMode : false,
13113 onFocus : Roo.emptyFn,
13115 hideMode:'offsets',
13123 * Protected method that will not generally be called directly. It
13124 * is called when the editor initializes the iframe with HTML contents. Override this method if you
13125 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
13127 getDocMarkup : function(){
13130 Roo.log(this.stylesheets);
13132 // inherit styels from page...??
13133 if (this.stylesheets === false) {
13135 Roo.get(document.head).select('style').each(function(node) {
13136 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
13139 Roo.get(document.head).select('link').each(function(node) {
13140 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
13143 } else if (!this.stylesheets.length) {
13145 st = '<style type="text/css">' +
13146 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
13149 Roo.each(this.stylesheets, function(s) {
13150 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
13155 st += '<style type="text/css">' +
13156 'IMG { cursor: pointer } ' +
13160 return '<html><head>' + st +
13161 //<style type="text/css">' +
13162 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
13164 ' </head><body class="roo-htmleditor-body"></body></html>';
13168 onRender : function(ct, position)
13171 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
13172 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
13175 this.el.dom.style.border = '0 none';
13176 this.el.dom.setAttribute('tabIndex', -1);
13177 this.el.addClass('x-hidden hide');
13181 if(Roo.isIE){ // fix IE 1px bogus margin
13182 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
13186 this.frameId = Roo.id();
13190 var iframe = this.owner.wrap.createChild({
13192 cls: 'form-control', // bootstrap..
13194 name: this.frameId,
13195 frameBorder : 'no',
13196 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
13201 this.iframe = iframe.dom;
13203 this.assignDocWin();
13205 this.doc.designMode = 'on';
13208 this.doc.write(this.getDocMarkup());
13212 var task = { // must defer to wait for browser to be ready
13214 //console.log("run task?" + this.doc.readyState);
13215 this.assignDocWin();
13216 if(this.doc.body || this.doc.readyState == 'complete'){
13218 this.doc.designMode="on";
13222 Roo.TaskMgr.stop(task);
13223 this.initEditor.defer(10, this);
13230 Roo.TaskMgr.start(task);
13237 onResize : function(w, h)
13239 Roo.log('resize: ' +w + ',' + h );
13240 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
13244 if(typeof w == 'number'){
13246 this.iframe.style.width = w + 'px';
13248 if(typeof h == 'number'){
13250 this.iframe.style.height = h + 'px';
13252 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
13259 * Toggles the editor between standard and source edit mode.
13260 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
13262 toggleSourceEdit : function(sourceEditMode){
13264 this.sourceEditMode = sourceEditMode === true;
13266 if(this.sourceEditMode){
13268 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
13271 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
13272 //this.iframe.className = '';
13275 //this.setSize(this.owner.wrap.getSize());
13276 //this.fireEvent('editmodechange', this, this.sourceEditMode);
13283 * Protected method that will not generally be called directly. If you need/want
13284 * custom HTML cleanup, this is the method you should override.
13285 * @param {String} html The HTML to be cleaned
13286 * return {String} The cleaned HTML
13288 cleanHtml : function(html){
13289 html = String(html);
13290 if(html.length > 5){
13291 if(Roo.isSafari){ // strip safari nonsense
13292 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
13295 if(html == ' '){
13302 * HTML Editor -> Textarea
13303 * Protected method that will not generally be called directly. Syncs the contents
13304 * of the editor iframe with the textarea.
13306 syncValue : function(){
13307 if(this.initialized){
13308 var bd = (this.doc.body || this.doc.documentElement);
13309 //this.cleanUpPaste(); -- this is done else where and causes havoc..
13310 var html = bd.innerHTML;
13312 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
13313 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
13315 html = '<div style="'+m[0]+'">' + html + '</div>';
13318 html = this.cleanHtml(html);
13319 // fix up the special chars.. normaly like back quotes in word...
13320 // however we do not want to do this with chinese..
13321 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
13322 var cc = b.charCodeAt();
13324 (cc >= 0x4E00 && cc < 0xA000 ) ||
13325 (cc >= 0x3400 && cc < 0x4E00 ) ||
13326 (cc >= 0xf900 && cc < 0xfb00 )
13332 if(this.owner.fireEvent('beforesync', this, html) !== false){
13333 this.el.dom.value = html;
13334 this.owner.fireEvent('sync', this, html);
13340 * Protected method that will not generally be called directly. Pushes the value of the textarea
13341 * into the iframe editor.
13343 pushValue : function(){
13344 if(this.initialized){
13345 var v = this.el.dom.value.trim();
13347 // if(v.length < 1){
13351 if(this.owner.fireEvent('beforepush', this, v) !== false){
13352 var d = (this.doc.body || this.doc.documentElement);
13354 this.cleanUpPaste();
13355 this.el.dom.value = d.innerHTML;
13356 this.owner.fireEvent('push', this, v);
13362 deferFocus : function(){
13363 this.focus.defer(10, this);
13367 focus : function(){
13368 if(this.win && !this.sourceEditMode){
13375 assignDocWin: function()
13377 var iframe = this.iframe;
13380 this.doc = iframe.contentWindow.document;
13381 this.win = iframe.contentWindow;
13383 if (!Roo.get(this.frameId)) {
13386 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
13387 this.win = Roo.get(this.frameId).dom.contentWindow;
13392 initEditor : function(){
13393 //console.log("INIT EDITOR");
13394 this.assignDocWin();
13398 this.doc.designMode="on";
13400 this.doc.write(this.getDocMarkup());
13403 var dbody = (this.doc.body || this.doc.documentElement);
13404 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
13405 // this copies styles from the containing element into thsi one..
13406 // not sure why we need all of this..
13407 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
13408 ss['background-attachment'] = 'fixed'; // w3c
13409 dbody.bgProperties = 'fixed'; // ie
13410 Roo.DomHelper.applyStyles(dbody, ss);
13411 Roo.EventManager.on(this.doc, {
13412 //'mousedown': this.onEditorEvent,
13413 'mouseup': this.onEditorEvent,
13414 'dblclick': this.onEditorEvent,
13415 'click': this.onEditorEvent,
13416 'keyup': this.onEditorEvent,
13421 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
13423 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
13424 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
13426 this.initialized = true;
13428 this.owner.fireEvent('initialize', this);
13433 onDestroy : function(){
13439 //for (var i =0; i < this.toolbars.length;i++) {
13440 // // fixme - ask toolbars for heights?
13441 // this.toolbars[i].onDestroy();
13444 //this.wrap.dom.innerHTML = '';
13445 //this.wrap.remove();
13450 onFirstFocus : function(){
13452 this.assignDocWin();
13455 this.activated = true;
13458 if(Roo.isGecko){ // prevent silly gecko errors
13460 var s = this.win.getSelection();
13461 if(!s.focusNode || s.focusNode.nodeType != 3){
13462 var r = s.getRangeAt(0);
13463 r.selectNodeContents((this.doc.body || this.doc.documentElement));
13468 this.execCmd('useCSS', true);
13469 this.execCmd('styleWithCSS', false);
13472 this.owner.fireEvent('activate', this);
13476 adjustFont: function(btn){
13477 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
13478 //if(Roo.isSafari){ // safari
13481 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
13482 if(Roo.isSafari){ // safari
13483 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
13484 v = (v < 10) ? 10 : v;
13485 v = (v > 48) ? 48 : v;
13486 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
13491 v = Math.max(1, v+adjust);
13493 this.execCmd('FontSize', v );
13496 onEditorEvent : function(e){
13497 this.owner.fireEvent('editorevent', this, e);
13498 // this.updateToolbar();
13499 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
13502 insertTag : function(tg)
13504 // could be a bit smarter... -> wrap the current selected tRoo..
13505 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
13507 range = this.createRange(this.getSelection());
13508 var wrappingNode = this.doc.createElement(tg.toLowerCase());
13509 wrappingNode.appendChild(range.extractContents());
13510 range.insertNode(wrappingNode);
13517 this.execCmd("formatblock", tg);
13521 insertText : function(txt)
13525 var range = this.createRange();
13526 range.deleteContents();
13527 //alert(Sender.getAttribute('label'));
13529 range.insertNode(this.doc.createTextNode(txt));
13535 * Executes a Midas editor command on the editor document and performs necessary focus and
13536 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
13537 * @param {String} cmd The Midas command
13538 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
13540 relayCmd : function(cmd, value){
13542 this.execCmd(cmd, value);
13543 this.owner.fireEvent('editorevent', this);
13544 //this.updateToolbar();
13545 this.owner.deferFocus();
13549 * Executes a Midas editor command directly on the editor document.
13550 * For visual commands, you should use {@link #relayCmd} instead.
13551 * <b>This should only be called after the editor is initialized.</b>
13552 * @param {String} cmd The Midas command
13553 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
13555 execCmd : function(cmd, value){
13556 this.doc.execCommand(cmd, false, value === undefined ? null : value);
13563 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
13565 * @param {String} text | dom node..
13567 insertAtCursor : function(text)
13572 if(!this.activated){
13578 var r = this.doc.selection.createRange();
13589 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
13593 // from jquery ui (MIT licenced)
13595 var win = this.win;
13597 if (win.getSelection && win.getSelection().getRangeAt) {
13598 range = win.getSelection().getRangeAt(0);
13599 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
13600 range.insertNode(node);
13601 } else if (win.document.selection && win.document.selection.createRange) {
13602 // no firefox support
13603 var txt = typeof(text) == 'string' ? text : text.outerHTML;
13604 win.document.selection.createRange().pasteHTML(txt);
13606 // no firefox support
13607 var txt = typeof(text) == 'string' ? text : text.outerHTML;
13608 this.execCmd('InsertHTML', txt);
13617 mozKeyPress : function(e){
13619 var c = e.getCharCode(), cmd;
13622 c = String.fromCharCode(c).toLowerCase();
13636 this.cleanUpPaste.defer(100, this);
13644 e.preventDefault();
13652 fixKeys : function(){ // load time branching for fastest keydown performance
13654 return function(e){
13655 var k = e.getKey(), r;
13658 r = this.doc.selection.createRange();
13661 r.pasteHTML('    ');
13668 r = this.doc.selection.createRange();
13670 var target = r.parentElement();
13671 if(!target || target.tagName.toLowerCase() != 'li'){
13673 r.pasteHTML('<br />');
13679 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
13680 this.cleanUpPaste.defer(100, this);
13686 }else if(Roo.isOpera){
13687 return function(e){
13688 var k = e.getKey();
13692 this.execCmd('InsertHTML','    ');
13695 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
13696 this.cleanUpPaste.defer(100, this);
13701 }else if(Roo.isSafari){
13702 return function(e){
13703 var k = e.getKey();
13707 this.execCmd('InsertText','\t');
13711 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
13712 this.cleanUpPaste.defer(100, this);
13720 getAllAncestors: function()
13722 var p = this.getSelectedNode();
13725 a.push(p); // push blank onto stack..
13726 p = this.getParentElement();
13730 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
13734 a.push(this.doc.body);
13738 lastSelNode : false,
13741 getSelection : function()
13743 this.assignDocWin();
13744 return Roo.isIE ? this.doc.selection : this.win.getSelection();
13747 getSelectedNode: function()
13749 // this may only work on Gecko!!!
13751 // should we cache this!!!!
13756 var range = this.createRange(this.getSelection()).cloneRange();
13759 var parent = range.parentElement();
13761 var testRange = range.duplicate();
13762 testRange.moveToElementText(parent);
13763 if (testRange.inRange(range)) {
13766 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
13769 parent = parent.parentElement;
13774 // is ancestor a text element.
13775 var ac = range.commonAncestorContainer;
13776 if (ac.nodeType == 3) {
13777 ac = ac.parentNode;
13780 var ar = ac.childNodes;
13783 var other_nodes = [];
13784 var has_other_nodes = false;
13785 for (var i=0;i<ar.length;i++) {
13786 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
13789 // fullly contained node.
13791 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
13796 // probably selected..
13797 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
13798 other_nodes.push(ar[i]);
13802 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
13807 has_other_nodes = true;
13809 if (!nodes.length && other_nodes.length) {
13810 nodes= other_nodes;
13812 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
13818 createRange: function(sel)
13820 // this has strange effects when using with
13821 // top toolbar - not sure if it's a great idea.
13822 //this.editor.contentWindow.focus();
13823 if (typeof sel != "undefined") {
13825 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
13827 return this.doc.createRange();
13830 return this.doc.createRange();
13833 getParentElement: function()
13836 this.assignDocWin();
13837 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
13839 var range = this.createRange(sel);
13842 var p = range.commonAncestorContainer;
13843 while (p.nodeType == 3) { // text node
13854 * Range intersection.. the hard stuff...
13858 * [ -- selected range --- ]
13862 * if end is before start or hits it. fail.
13863 * if start is after end or hits it fail.
13865 * if either hits (but other is outside. - then it's not
13871 // @see http://www.thismuchiknow.co.uk/?p=64.
13872 rangeIntersectsNode : function(range, node)
13874 var nodeRange = node.ownerDocument.createRange();
13876 nodeRange.selectNode(node);
13878 nodeRange.selectNodeContents(node);
13881 var rangeStartRange = range.cloneRange();
13882 rangeStartRange.collapse(true);
13884 var rangeEndRange = range.cloneRange();
13885 rangeEndRange.collapse(false);
13887 var nodeStartRange = nodeRange.cloneRange();
13888 nodeStartRange.collapse(true);
13890 var nodeEndRange = nodeRange.cloneRange();
13891 nodeEndRange.collapse(false);
13893 return rangeStartRange.compareBoundaryPoints(
13894 Range.START_TO_START, nodeEndRange) == -1 &&
13895 rangeEndRange.compareBoundaryPoints(
13896 Range.START_TO_START, nodeStartRange) == 1;
13900 rangeCompareNode : function(range, node)
13902 var nodeRange = node.ownerDocument.createRange();
13904 nodeRange.selectNode(node);
13906 nodeRange.selectNodeContents(node);
13910 range.collapse(true);
13912 nodeRange.collapse(true);
13914 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
13915 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
13917 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
13919 var nodeIsBefore = ss == 1;
13920 var nodeIsAfter = ee == -1;
13922 if (nodeIsBefore && nodeIsAfter)
13924 if (!nodeIsBefore && nodeIsAfter)
13925 return 1; //right trailed.
13927 if (nodeIsBefore && !nodeIsAfter)
13928 return 2; // left trailed.
13933 // private? - in a new class?
13934 cleanUpPaste : function()
13936 // cleans up the whole document..
13937 Roo.log('cleanuppaste');
13939 this.cleanUpChildren(this.doc.body);
13940 var clean = this.cleanWordChars(this.doc.body.innerHTML);
13941 if (clean != this.doc.body.innerHTML) {
13942 this.doc.body.innerHTML = clean;
13947 cleanWordChars : function(input) {// change the chars to hex code
13948 var he = Roo.HtmlEditorCore;
13950 var output = input;
13951 Roo.each(he.swapCodes, function(sw) {
13952 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
13954 output = output.replace(swapper, sw[1]);
13961 cleanUpChildren : function (n)
13963 if (!n.childNodes.length) {
13966 for (var i = n.childNodes.length-1; i > -1 ; i--) {
13967 this.cleanUpChild(n.childNodes[i]);
13974 cleanUpChild : function (node)
13977 //console.log(node);
13978 if (node.nodeName == "#text") {
13979 // clean up silly Windows -- stuff?
13982 if (node.nodeName == "#comment") {
13983 node.parentNode.removeChild(node);
13984 // clean up silly Windows -- stuff?
13988 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
13990 node.parentNode.removeChild(node);
13995 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
13997 // remove <a name=....> as rendering on yahoo mailer is borked with this.
13998 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
14000 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
14001 // remove_keep_children = true;
14004 if (remove_keep_children) {
14005 this.cleanUpChildren(node);
14006 // inserts everything just before this node...
14007 while (node.childNodes.length) {
14008 var cn = node.childNodes[0];
14009 node.removeChild(cn);
14010 node.parentNode.insertBefore(cn, node);
14012 node.parentNode.removeChild(node);
14016 if (!node.attributes || !node.attributes.length) {
14017 this.cleanUpChildren(node);
14021 function cleanAttr(n,v)
14024 if (v.match(/^\./) || v.match(/^\//)) {
14027 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
14030 if (v.match(/^#/)) {
14033 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
14034 node.removeAttribute(n);
14038 function cleanStyle(n,v)
14040 if (v.match(/expression/)) { //XSS?? should we even bother..
14041 node.removeAttribute(n);
14044 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
14045 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
14048 var parts = v.split(/;/);
14051 Roo.each(parts, function(p) {
14052 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
14056 var l = p.split(':').shift().replace(/\s+/g,'');
14057 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
14059 if ( cblack.indexOf(l) > -1) {
14060 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
14061 //node.removeAttribute(n);
14065 // only allow 'c whitelisted system attributes'
14066 if ( cwhite.length && cwhite.indexOf(l) < 0) {
14067 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
14068 //node.removeAttribute(n);
14078 if (clean.length) {
14079 node.setAttribute(n, clean.join(';'));
14081 node.removeAttribute(n);
14087 for (var i = node.attributes.length-1; i > -1 ; i--) {
14088 var a = node.attributes[i];
14091 if (a.name.toLowerCase().substr(0,2)=='on') {
14092 node.removeAttribute(a.name);
14095 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
14096 node.removeAttribute(a.name);
14099 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
14100 cleanAttr(a.name,a.value); // fixme..
14103 if (a.name == 'style') {
14104 cleanStyle(a.name,a.value);
14107 /// clean up MS crap..
14108 // tecnically this should be a list of valid class'es..
14111 if (a.name == 'class') {
14112 if (a.value.match(/^Mso/)) {
14113 node.className = '';
14116 if (a.value.match(/body/)) {
14117 node.className = '';
14128 this.cleanUpChildren(node);
14134 // hide stuff that is not compatible
14148 * @event specialkey
14152 * @cfg {String} fieldClass @hide
14155 * @cfg {String} focusClass @hide
14158 * @cfg {String} autoCreate @hide
14161 * @cfg {String} inputType @hide
14164 * @cfg {String} invalidClass @hide
14167 * @cfg {String} invalidText @hide
14170 * @cfg {String} msgFx @hide
14173 * @cfg {String} validateOnBlur @hide
14177 Roo.HtmlEditorCore.white = [
14178 'area', 'br', 'img', 'input', 'hr', 'wbr',
14180 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
14181 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
14182 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
14183 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
14184 'table', 'ul', 'xmp',
14186 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
14189 'dir', 'menu', 'ol', 'ul', 'dl',
14195 Roo.HtmlEditorCore.black = [
14196 // 'embed', 'object', // enable - backend responsiblity to clean thiese
14198 'base', 'basefont', 'bgsound', 'blink', 'body',
14199 'frame', 'frameset', 'head', 'html', 'ilayer',
14200 'iframe', 'layer', 'link', 'meta', 'object',
14201 'script', 'style' ,'title', 'xml' // clean later..
14203 Roo.HtmlEditorCore.clean = [
14204 'script', 'style', 'title', 'xml'
14206 Roo.HtmlEditorCore.remove = [
14211 Roo.HtmlEditorCore.ablack = [
14215 Roo.HtmlEditorCore.aclean = [
14216 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
14220 Roo.HtmlEditorCore.pwhite= [
14221 'http', 'https', 'mailto'
14224 // white listed style attributes.
14225 Roo.HtmlEditorCore.cwhite= [
14226 // 'text-align', /// default is to allow most things..
14232 // black listed style attributes.
14233 Roo.HtmlEditorCore.cblack= [
14234 // 'font-size' -- this can be set by the project
14238 Roo.HtmlEditorCore.swapCodes =[
14257 * @class Roo.bootstrap.HtmlEditor
14258 * @extends Roo.bootstrap.TextArea
14259 * Bootstrap HtmlEditor class
14262 * Create a new HtmlEditor
14263 * @param {Object} config The config object
14266 Roo.bootstrap.HtmlEditor = function(config){
14267 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
14268 if (!this.toolbars) {
14269 this.toolbars = [];
14271 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
14274 * @event initialize
14275 * Fires when the editor is fully initialized (including the iframe)
14276 * @param {HtmlEditor} this
14281 * Fires when the editor is first receives the focus. Any insertion must wait
14282 * until after this event.
14283 * @param {HtmlEditor} this
14287 * @event beforesync
14288 * Fires before the textarea is updated with content from the editor iframe. Return false
14289 * to cancel the sync.
14290 * @param {HtmlEditor} this
14291 * @param {String} html
14295 * @event beforepush
14296 * Fires before the iframe editor is updated with content from the textarea. Return false
14297 * to cancel the push.
14298 * @param {HtmlEditor} this
14299 * @param {String} html
14304 * Fires when the textarea is updated with content from the editor iframe.
14305 * @param {HtmlEditor} this
14306 * @param {String} html
14311 * Fires when the iframe editor is updated with content from the textarea.
14312 * @param {HtmlEditor} this
14313 * @param {String} html
14317 * @event editmodechange
14318 * Fires when the editor switches edit modes
14319 * @param {HtmlEditor} this
14320 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
14322 editmodechange: true,
14324 * @event editorevent
14325 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
14326 * @param {HtmlEditor} this
14330 * @event firstfocus
14331 * Fires when on first focus - needed by toolbars..
14332 * @param {HtmlEditor} this
14337 * Auto save the htmlEditor value as a file into Events
14338 * @param {HtmlEditor} this
14342 * @event savedpreview
14343 * preview the saved version of htmlEditor
14344 * @param {HtmlEditor} this
14351 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
14355 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
14360 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
14365 * @cfg {Number} height (in pixels)
14369 * @cfg {Number} width (in pixels)
14374 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
14377 stylesheets: false,
14382 // private properties
14383 validationEvent : false,
14385 initialized : false,
14388 onFocus : Roo.emptyFn,
14390 hideMode:'offsets',
14393 tbContainer : false,
14395 toolbarContainer :function() {
14396 return this.wrap.select('.x-html-editor-tb',true).first();
14400 * Protected method that will not generally be called directly. It
14401 * is called when the editor creates its toolbar. Override this method if you need to
14402 * add custom toolbar buttons.
14403 * @param {HtmlEditor} editor
14405 createToolbar : function(){
14407 Roo.log("create toolbars");
14409 this.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard({editor: this} ) ];
14410 this.toolbars[0].render(this.toolbarContainer());
14414 // if (!editor.toolbars || !editor.toolbars.length) {
14415 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
14418 // for (var i =0 ; i < editor.toolbars.length;i++) {
14419 // editor.toolbars[i] = Roo.factory(
14420 // typeof(editor.toolbars[i]) == 'string' ?
14421 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
14422 // Roo.bootstrap.HtmlEditor);
14423 // editor.toolbars[i].init(editor);
14429 onRender : function(ct, position)
14431 // Roo.log("Call onRender: " + this.xtype);
14433 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
14435 this.wrap = this.inputEl().wrap({
14436 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
14439 this.editorcore.onRender(ct, position);
14441 if (this.resizable) {
14442 this.resizeEl = new Roo.Resizable(this.wrap, {
14446 minHeight : this.height,
14447 height: this.height,
14448 handles : this.resizable,
14451 resize : function(r, w, h) {
14452 _t.onResize(w,h); // -something
14458 this.createToolbar(this);
14461 if(!this.width && this.resizable){
14462 this.setSize(this.wrap.getSize());
14464 if (this.resizeEl) {
14465 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
14466 // should trigger onReize..
14472 onResize : function(w, h)
14474 Roo.log('resize: ' +w + ',' + h );
14475 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
14479 if(this.inputEl() ){
14480 if(typeof w == 'number'){
14481 var aw = w - this.wrap.getFrameWidth('lr');
14482 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
14485 if(typeof h == 'number'){
14486 var tbh = -11; // fixme it needs to tool bar size!
14487 for (var i =0; i < this.toolbars.length;i++) {
14488 // fixme - ask toolbars for heights?
14489 tbh += this.toolbars[i].el.getHeight();
14490 //if (this.toolbars[i].footer) {
14491 // tbh += this.toolbars[i].footer.el.getHeight();
14499 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
14500 ah -= 5; // knock a few pixes off for look..
14501 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
14505 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
14506 this.editorcore.onResize(ew,eh);
14511 * Toggles the editor between standard and source edit mode.
14512 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
14514 toggleSourceEdit : function(sourceEditMode)
14516 this.editorcore.toggleSourceEdit(sourceEditMode);
14518 if(this.editorcore.sourceEditMode){
14519 Roo.log('editor - showing textarea');
14522 // Roo.log(this.syncValue());
14524 this.inputEl().removeClass('hide');
14525 this.inputEl().dom.removeAttribute('tabIndex');
14526 this.inputEl().focus();
14528 Roo.log('editor - hiding textarea');
14530 // Roo.log(this.pushValue());
14533 this.inputEl().addClass('hide');
14534 this.inputEl().dom.setAttribute('tabIndex', -1);
14535 //this.deferFocus();
14538 if(this.resizable){
14539 this.setSize(this.wrap.getSize());
14542 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
14545 // private (for BoxComponent)
14546 adjustSize : Roo.BoxComponent.prototype.adjustSize,
14548 // private (for BoxComponent)
14549 getResizeEl : function(){
14553 // private (for BoxComponent)
14554 getPositionEl : function(){
14559 initEvents : function(){
14560 this.originalValue = this.getValue();
14564 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
14567 // markInvalid : Roo.emptyFn,
14569 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
14572 // clearInvalid : Roo.emptyFn,
14574 setValue : function(v){
14575 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
14576 this.editorcore.pushValue();
14581 deferFocus : function(){
14582 this.focus.defer(10, this);
14586 focus : function(){
14587 this.editorcore.focus();
14593 onDestroy : function(){
14599 for (var i =0; i < this.toolbars.length;i++) {
14600 // fixme - ask toolbars for heights?
14601 this.toolbars[i].onDestroy();
14604 this.wrap.dom.innerHTML = '';
14605 this.wrap.remove();
14610 onFirstFocus : function(){
14611 //Roo.log("onFirstFocus");
14612 this.editorcore.onFirstFocus();
14613 for (var i =0; i < this.toolbars.length;i++) {
14614 this.toolbars[i].onFirstFocus();
14620 syncValue : function()
14622 this.editorcore.syncValue();
14625 pushValue : function()
14627 this.editorcore.pushValue();
14631 // hide stuff that is not compatible
14645 * @event specialkey
14649 * @cfg {String} fieldClass @hide
14652 * @cfg {String} focusClass @hide
14655 * @cfg {String} autoCreate @hide
14658 * @cfg {String} inputType @hide
14661 * @cfg {String} invalidClass @hide
14664 * @cfg {String} invalidText @hide
14667 * @cfg {String} msgFx @hide
14670 * @cfg {String} validateOnBlur @hide
14681 * @class Roo.bootstrap.HtmlEditorToolbar1
14686 new Roo.bootstrap.HtmlEditor({
14689 new Roo.bootstrap.HtmlEditorToolbar1({
14690 disable : { fonts: 1 , format: 1, ..., ... , ...],
14696 * @cfg {Object} disable List of elements to disable..
14697 * @cfg {Array} btns List of additional buttons.
14701 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
14704 Roo.bootstrap.HtmlEditor.ToolbarStandard = function(config)
14707 Roo.apply(this, config);
14709 // default disabled, based on 'good practice'..
14710 this.disable = this.disable || {};
14711 Roo.applyIf(this.disable, {
14714 specialElements : true
14716 Roo.bootstrap.HtmlEditor.ToolbarStandard.superclass.constructor.call(this, config);
14718 this.editor = config.editor;
14719 this.editorcore = config.editor.editorcore;
14721 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
14723 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
14724 // dont call parent... till later.
14726 Roo.extend(Roo.bootstrap.HtmlEditor.ToolbarStandard, Roo.bootstrap.Navbar, {
14732 editorcore : false,
14737 "h1","h2","h3","h4","h5","h6",
14739 "abbr", "acronym", "address", "cite", "samp", "var",
14743 onRender : function(ct, position)
14745 // Roo.log("Call onRender: " + this.xtype);
14747 Roo.bootstrap.HtmlEditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
14749 this.el.dom.style.marginBottom = '0';
14751 var editorcore = this.editorcore;
14752 var editor= this.editor;
14755 var btn = function(id,cmd , toggle, handler){
14757 var event = toggle ? 'toggle' : 'click';
14762 xns: Roo.bootstrap,
14765 enableToggle:toggle !== false,
14767 pressed : toggle ? false : null,
14770 a.listeners[toggle ? 'toggle' : 'click'] = function() {
14771 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
14780 xns: Roo.bootstrap,
14781 glyphicon : 'font',
14785 xns: Roo.bootstrap,
14789 Roo.each(this.formats, function(f) {
14790 style.menu.items.push({
14792 xns: Roo.bootstrap,
14793 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
14798 editorcore.insertTag(this.tagname);
14805 children.push(style);
14808 btn('bold',false,true);
14809 btn('italic',false,true);
14810 btn('align-left', 'justifyleft',true);
14811 btn('align-center', 'justifycenter',true);
14812 btn('align-right' , 'justifyright',true);
14813 btn('link', false, false, function(btn) {
14814 //Roo.log("create link?");
14815 var url = prompt(this.createLinkText, this.defaultLinkValue);
14816 if(url && url != 'http:/'+'/'){
14817 this.editorcore.relayCmd('createlink', url);
14820 btn('list','insertunorderedlist',true);
14821 btn('pencil', false,true, function(btn){
14824 this.toggleSourceEdit(btn.pressed);
14830 xns: Roo.bootstrap,
14835 xns: Roo.bootstrap,
14840 cog.menu.items.push({
14842 xns: Roo.bootstrap,
14843 html : Clean styles,
14848 editorcore.insertTag(this.tagname);
14857 this.xtype = 'Navbar';
14859 for(var i=0;i< children.length;i++) {
14861 this.buttons.add(this.addxtypeChild(children[i]));
14865 editor.on('editorevent', this.updateToolbar, this);
14867 onBtnClick : function(id)
14869 this.editorcore.relayCmd(id);
14870 this.editorcore.focus();
14874 * Protected method that will not generally be called directly. It triggers
14875 * a toolbar update by reading the markup state of the current selection in the editor.
14877 updateToolbar: function(){
14879 if(!this.editorcore.activated){
14880 this.editor.onFirstFocus(); // is this neeed?
14884 var btns = this.buttons;
14885 var doc = this.editorcore.doc;
14886 btns.get('bold').setActive(doc.queryCommandState('bold'));
14887 btns.get('italic').setActive(doc.queryCommandState('italic'));
14888 //btns.get('underline').setActive(doc.queryCommandState('underline'));
14890 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
14891 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
14892 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
14894 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
14895 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
14898 var ans = this.editorcore.getAllAncestors();
14899 if (this.formatCombo) {
14902 var store = this.formatCombo.store;
14903 this.formatCombo.setValue("");
14904 for (var i =0; i < ans.length;i++) {
14905 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
14907 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
14915 // hides menus... - so this cant be on a menu...
14916 Roo.bootstrap.MenuMgr.hideAll();
14918 Roo.bootstrap.MenuMgr.hideAll();
14919 //this.editorsyncValue();
14921 onFirstFocus: function() {
14922 this.buttons.each(function(item){
14926 toggleSourceEdit : function(sourceEditMode){
14929 if(sourceEditMode){
14930 Roo.log("disabling buttons");
14931 this.buttons.each( function(item){
14932 if(item.cmd != 'pencil'){
14938 Roo.log("enabling buttons");
14939 if(this.editorcore.initialized){
14940 this.buttons.each( function(item){
14946 Roo.log("calling toggole on editor");
14947 // tell the editor that it's been pressed..
14948 this.editor.toggleSourceEdit(sourceEditMode);
14958 * @class Roo.bootstrap.Table.AbstractSelectionModel
14959 * @extends Roo.util.Observable
14960 * Abstract base class for grid SelectionModels. It provides the interface that should be
14961 * implemented by descendant classes. This class should not be directly instantiated.
14964 Roo.bootstrap.Table.AbstractSelectionModel = function(){
14965 this.locked = false;
14966 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
14970 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
14971 /** @ignore Called by the grid automatically. Do not call directly. */
14972 init : function(grid){
14978 * Locks the selections.
14981 this.locked = true;
14985 * Unlocks the selections.
14987 unlock : function(){
14988 this.locked = false;
14992 * Returns true if the selections are locked.
14993 * @return {Boolean}
14995 isLocked : function(){
14996 return this.locked;
15000 * @class Roo.bootstrap.Table.ColumnModel
15001 * @extends Roo.util.Observable
15002 * This is the default implementation of a ColumnModel used by the bootstrap table. It defines
15003 * the columns in the table.
15006 * @param {Object} config An Array of column config objects. See this class's
15007 * config objects for details.
15009 Roo.bootstrap.Table.ColumnModel = function(config){
15011 * The config passed into the constructor
15013 this.config = config;
15016 // if no id, create one
15017 // if the column does not have a dataIndex mapping,
15018 // map it to the order it is in the config
15019 for(var i = 0, len = config.length; i < len; i++){
15021 if(typeof c.dataIndex == "undefined"){
15024 if(typeof c.renderer == "string"){
15025 c.renderer = Roo.util.Format[c.renderer];
15027 if(typeof c.id == "undefined"){
15030 // if(c.editor && c.editor.xtype){
15031 // c.editor = Roo.factory(c.editor, Roo.grid);
15033 // if(c.editor && c.editor.isFormField){
15034 // c.editor = new Roo.grid.GridEditor(c.editor);
15037 this.lookup[c.id] = c;
15041 * The width of columns which have no width specified (defaults to 100)
15044 this.defaultWidth = 100;
15047 * Default sortable of columns which have no sortable specified (defaults to false)
15050 this.defaultSortable = false;
15054 * @event widthchange
15055 * Fires when the width of a column changes.
15056 * @param {ColumnModel} this
15057 * @param {Number} columnIndex The column index
15058 * @param {Number} newWidth The new width
15060 "widthchange": true,
15062 * @event headerchange
15063 * Fires when the text of a header changes.
15064 * @param {ColumnModel} this
15065 * @param {Number} columnIndex The column index
15066 * @param {Number} newText The new header text
15068 "headerchange": true,
15070 * @event hiddenchange
15071 * Fires when a column is hidden or "unhidden".
15072 * @param {ColumnModel} this
15073 * @param {Number} columnIndex The column index
15074 * @param {Boolean} hidden true if hidden, false otherwise
15076 "hiddenchange": true,
15078 * @event columnmoved
15079 * Fires when a column is moved.
15080 * @param {ColumnModel} this
15081 * @param {Number} oldIndex
15082 * @param {Number} newIndex
15084 "columnmoved" : true,
15086 * @event columlockchange
15087 * Fires when a column's locked state is changed
15088 * @param {ColumnModel} this
15089 * @param {Number} colIndex
15090 * @param {Boolean} locked true if locked
15092 "columnlockchange" : true
15094 Roo.bootstrap.Table.ColumnModel.superclass.constructor.call(this);
15096 Roo.extend(Roo.bootstrap.Table.ColumnModel, Roo.util.Observable, {
15098 * @cfg {String} header The header text to display in the Grid view.
15101 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
15102 * {@link Roo.data.Record} definition from which to draw the column's value. If not
15103 * specified, the column's index is used as an index into the Record's data Array.
15106 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
15107 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
15110 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
15111 * Defaults to the value of the {@link #defaultSortable} property.
15112 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
15115 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
15118 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
15121 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
15124 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
15127 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
15128 * given the cell's data value. See {@link #setRenderer}. If not specified, the
15129 * default renderer uses the raw data value.
15132 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
15136 * Returns the id of the column at the specified index.
15137 * @param {Number} index The column index
15138 * @return {String} the id
15140 getColumnId : function(index){
15141 return this.config[index].id;
15145 * Returns the column for a specified id.
15146 * @param {String} id The column id
15147 * @return {Object} the column
15149 getColumnById : function(id){
15150 return this.lookup[id];
15155 * Returns the column for a specified dataIndex.
15156 * @param {String} dataIndex The column dataIndex
15157 * @return {Object|Boolean} the column or false if not found
15159 getColumnByDataIndex: function(dataIndex){
15160 var index = this.findColumnIndex(dataIndex);
15161 return index > -1 ? this.config[index] : false;
15165 * Returns the index for a specified column id.
15166 * @param {String} id The column id
15167 * @return {Number} the index, or -1 if not found
15169 getIndexById : function(id){
15170 for(var i = 0, len = this.config.length; i < len; i++){
15171 if(this.config[i].id == id){
15179 * Returns the index for a specified column dataIndex.
15180 * @param {String} dataIndex The column dataIndex
15181 * @return {Number} the index, or -1 if not found
15184 findColumnIndex : function(dataIndex){
15185 for(var i = 0, len = this.config.length; i < len; i++){
15186 if(this.config[i].dataIndex == dataIndex){
15194 moveColumn : function(oldIndex, newIndex){
15195 var c = this.config[oldIndex];
15196 this.config.splice(oldIndex, 1);
15197 this.config.splice(newIndex, 0, c);
15198 this.dataMap = null;
15199 this.fireEvent("columnmoved", this, oldIndex, newIndex);
15202 isLocked : function(colIndex){
15203 return this.config[colIndex].locked === true;
15206 setLocked : function(colIndex, value, suppressEvent){
15207 if(this.isLocked(colIndex) == value){
15210 this.config[colIndex].locked = value;
15211 if(!suppressEvent){
15212 this.fireEvent("columnlockchange", this, colIndex, value);
15216 getTotalLockedWidth : function(){
15217 var totalWidth = 0;
15218 for(var i = 0; i < this.config.length; i++){
15219 if(this.isLocked(i) && !this.isHidden(i)){
15220 this.totalWidth += this.getColumnWidth(i);
15226 getLockedCount : function(){
15227 for(var i = 0, len = this.config.length; i < len; i++){
15228 if(!this.isLocked(i)){
15235 * Returns the number of columns.
15238 getColumnCount : function(visibleOnly){
15239 if(visibleOnly === true){
15241 for(var i = 0, len = this.config.length; i < len; i++){
15242 if(!this.isHidden(i)){
15248 return this.config.length;
15252 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
15253 * @param {Function} fn
15254 * @param {Object} scope (optional)
15255 * @return {Array} result
15257 getColumnsBy : function(fn, scope){
15259 for(var i = 0, len = this.config.length; i < len; i++){
15260 var c = this.config[i];
15261 if(fn.call(scope||this, c, i) === true){
15269 * Returns true if the specified column is sortable.
15270 * @param {Number} col The column index
15271 * @return {Boolean}
15273 isSortable : function(col){
15274 if(typeof this.config[col].sortable == "undefined"){
15275 return this.defaultSortable;
15277 return this.config[col].sortable;
15281 * Returns the rendering (formatting) function defined for the column.
15282 * @param {Number} col The column index.
15283 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
15285 getRenderer : function(col){
15286 if(!this.config[col].renderer){
15287 return Roo.bootstrap.Table.ColumnModel.defaultRenderer;
15289 return this.config[col].renderer;
15293 * Sets the rendering (formatting) function for a column.
15294 * @param {Number} col The column index
15295 * @param {Function} fn The function to use to process the cell's raw data
15296 * to return HTML markup for the grid view. The render function is called with
15297 * the following parameters:<ul>
15298 * <li>Data value.</li>
15299 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
15300 * <li>css A CSS style string to apply to the table cell.</li>
15301 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
15302 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
15303 * <li>Row index</li>
15304 * <li>Column index</li>
15305 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
15307 setRenderer : function(col, fn){
15308 this.config[col].renderer = fn;
15312 * Returns the width for the specified column.
15313 * @param {Number} col The column index
15316 getColumnWidth : function(col){
15317 return this.config[col].width * 1 || this.defaultWidth;
15321 * Sets the width for a column.
15322 * @param {Number} col The column index
15323 * @param {Number} width The new width
15325 setColumnWidth : function(col, width, suppressEvent){
15326 this.config[col].width = width;
15327 this.totalWidth = null;
15328 if(!suppressEvent){
15329 this.fireEvent("widthchange", this, col, width);
15334 * Returns the total width of all columns.
15335 * @param {Boolean} includeHidden True to include hidden column widths
15338 getTotalWidth : function(includeHidden){
15339 if(!this.totalWidth){
15340 this.totalWidth = 0;
15341 for(var i = 0, len = this.config.length; i < len; i++){
15342 if(includeHidden || !this.isHidden(i)){
15343 this.totalWidth += this.getColumnWidth(i);
15347 return this.totalWidth;
15351 * Returns the header for the specified column.
15352 * @param {Number} col The column index
15355 getColumnHeader : function(col){
15356 return this.config[col].header;
15360 * Sets the header for a column.
15361 * @param {Number} col The column index
15362 * @param {String} header The new header
15364 setColumnHeader : function(col, header){
15365 this.config[col].header = header;
15366 this.fireEvent("headerchange", this, col, header);
15370 * Returns the tooltip for the specified column.
15371 * @param {Number} col The column index
15374 getColumnTooltip : function(col){
15375 return this.config[col].tooltip;
15378 * Sets the tooltip for a column.
15379 * @param {Number} col The column index
15380 * @param {String} tooltip The new tooltip
15382 setColumnTooltip : function(col, tooltip){
15383 this.config[col].tooltip = tooltip;
15387 * Returns the dataIndex for the specified column.
15388 * @param {Number} col The column index
15391 getDataIndex : function(col){
15392 return this.config[col].dataIndex;
15396 * Sets the dataIndex for a column.
15397 * @param {Number} col The column index
15398 * @param {Number} dataIndex The new dataIndex
15400 setDataIndex : function(col, dataIndex){
15401 this.config[col].dataIndex = dataIndex;
15407 * Returns true if the cell is editable.
15408 * @param {Number} colIndex The column index
15409 * @param {Number} rowIndex The row index
15410 * @return {Boolean}
15412 isCellEditable : function(colIndex, rowIndex){
15413 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
15417 * Returns the editor defined for the cell/column.
15418 * return false or null to disable editing.
15419 * @param {Number} colIndex The column index
15420 * @param {Number} rowIndex The row index
15423 getCellEditor : function(colIndex, rowIndex){
15424 return this.config[colIndex].editor;
15428 * Sets if a column is editable.
15429 * @param {Number} col The column index
15430 * @param {Boolean} editable True if the column is editable
15432 setEditable : function(col, editable){
15433 this.config[col].editable = editable;
15438 * Returns true if the column is hidden.
15439 * @param {Number} colIndex The column index
15440 * @return {Boolean}
15442 isHidden : function(colIndex){
15443 return this.config[colIndex].hidden;
15448 * Returns true if the column width cannot be changed
15450 isFixed : function(colIndex){
15451 return this.config[colIndex].fixed;
15455 * Returns true if the column can be resized
15456 * @return {Boolean}
15458 isResizable : function(colIndex){
15459 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
15462 * Sets if a column is hidden.
15463 * @param {Number} colIndex The column index
15464 * @param {Boolean} hidden True if the column is hidden
15466 setHidden : function(colIndex, hidden){
15467 this.config[colIndex].hidden = hidden;
15468 this.totalWidth = null;
15469 this.fireEvent("hiddenchange", this, colIndex, hidden);
15473 * Sets the editor for a column.
15474 * @param {Number} col The column index
15475 * @param {Object} editor The editor object
15477 setEditor : function(col, editor){
15478 this.config[col].editor = editor;
15482 Roo.bootstrap.Table.ColumnModel.defaultRenderer = function(value){
15483 if(typeof value == "string" && value.length < 1){
15489 // Alias for backwards compatibility
15490 Roo.bootstrap.Table.DefaultColumnModel = Roo.bootstrap.Table.ColumnModel;
15493 * @extends Roo.bootstrap.Table.AbstractSelectionModel
15494 * @class Roo.bootstrap.Table.RowSelectionModel
15495 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
15496 * It supports multiple selections and keyboard selection/navigation.
15498 * @param {Object} config
15501 Roo.bootstrap.Table.RowSelectionModel = function(config){
15502 Roo.apply(this, config);
15503 this.selections = new Roo.util.MixedCollection(false, function(o){
15508 this.lastActive = false;
15512 * @event selectionchange
15513 * Fires when the selection changes
15514 * @param {SelectionModel} this
15516 "selectionchange" : true,
15518 * @event afterselectionchange
15519 * Fires after the selection changes (eg. by key press or clicking)
15520 * @param {SelectionModel} this
15522 "afterselectionchange" : true,
15524 * @event beforerowselect
15525 * Fires when a row is selected being selected, return false to cancel.
15526 * @param {SelectionModel} this
15527 * @param {Number} rowIndex The selected index
15528 * @param {Boolean} keepExisting False if other selections will be cleared
15530 "beforerowselect" : true,
15533 * Fires when a row is selected.
15534 * @param {SelectionModel} this
15535 * @param {Number} rowIndex The selected index
15536 * @param {Roo.data.Record} r The record
15538 "rowselect" : true,
15540 * @event rowdeselect
15541 * Fires when a row is deselected.
15542 * @param {SelectionModel} this
15543 * @param {Number} rowIndex The selected index
15545 "rowdeselect" : true
15547 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
15548 this.locked = false;
15551 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
15553 * @cfg {Boolean} singleSelect
15554 * True to allow selection of only one row at a time (defaults to false)
15556 singleSelect : false,
15559 initEvents : function(){
15561 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
15562 this.grid.on("mousedown", this.handleMouseDown, this);
15563 }else{ // allow click to work like normal
15564 this.grid.on("rowclick", this.handleDragableRowClick, this);
15567 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
15568 "up" : function(e){
15570 this.selectPrevious(e.shiftKey);
15571 }else if(this.last !== false && this.lastActive !== false){
15572 var last = this.last;
15573 this.selectRange(this.last, this.lastActive-1);
15574 this.grid.getView().focusRow(this.lastActive);
15575 if(last !== false){
15579 this.selectFirstRow();
15581 this.fireEvent("afterselectionchange", this);
15583 "down" : function(e){
15585 this.selectNext(e.shiftKey);
15586 }else if(this.last !== false && this.lastActive !== false){
15587 var last = this.last;
15588 this.selectRange(this.last, this.lastActive+1);
15589 this.grid.getView().focusRow(this.lastActive);
15590 if(last !== false){
15594 this.selectFirstRow();
15596 this.fireEvent("afterselectionchange", this);
15601 var view = this.grid.view;
15602 view.on("refresh", this.onRefresh, this);
15603 view.on("rowupdated", this.onRowUpdated, this);
15604 view.on("rowremoved", this.onRemove, this);
15608 onRefresh : function(){
15609 var ds = this.grid.dataSource, i, v = this.grid.view;
15610 var s = this.selections;
15611 s.each(function(r){
15612 if((i = ds.indexOfId(r.id)) != -1){
15621 onRemove : function(v, index, r){
15622 this.selections.remove(r);
15626 onRowUpdated : function(v, index, r){
15627 if(this.isSelected(r)){
15628 v.onRowSelect(index);
15634 * @param {Array} records The records to select
15635 * @param {Boolean} keepExisting (optional) True to keep existing selections
15637 selectRecords : function(records, keepExisting){
15639 this.clearSelections();
15641 var ds = this.grid.dataSource;
15642 for(var i = 0, len = records.length; i < len; i++){
15643 this.selectRow(ds.indexOf(records[i]), true);
15648 * Gets the number of selected rows.
15651 getCount : function(){
15652 return this.selections.length;
15656 * Selects the first row in the grid.
15658 selectFirstRow : function(){
15663 * Select the last row.
15664 * @param {Boolean} keepExisting (optional) True to keep existing selections
15666 selectLastRow : function(keepExisting){
15667 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
15671 * Selects the row immediately following the last selected row.
15672 * @param {Boolean} keepExisting (optional) True to keep existing selections
15674 selectNext : function(keepExisting){
15675 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
15676 this.selectRow(this.last+1, keepExisting);
15677 this.grid.getView().focusRow(this.last);
15682 * Selects the row that precedes the last selected row.
15683 * @param {Boolean} keepExisting (optional) True to keep existing selections
15685 selectPrevious : function(keepExisting){
15687 this.selectRow(this.last-1, keepExisting);
15688 this.grid.getView().focusRow(this.last);
15693 * Returns the selected records
15694 * @return {Array} Array of selected records
15696 getSelections : function(){
15697 return [].concat(this.selections.items);
15701 * Returns the first selected record.
15704 getSelected : function(){
15705 return this.selections.itemAt(0);
15710 * Clears all selections.
15712 clearSelections : function(fast){
15713 if(this.locked) return;
15715 var ds = this.grid.dataSource;
15716 var s = this.selections;
15717 s.each(function(r){
15718 this.deselectRow(ds.indexOfId(r.id));
15722 this.selections.clear();
15729 * Selects all rows.
15731 selectAll : function(){
15732 if(this.locked) return;
15733 this.selections.clear();
15734 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
15735 this.selectRow(i, true);
15740 * Returns True if there is a selection.
15741 * @return {Boolean}
15743 hasSelection : function(){
15744 return this.selections.length > 0;
15748 * Returns True if the specified row is selected.
15749 * @param {Number/Record} record The record or index of the record to check
15750 * @return {Boolean}
15752 isSelected : function(index){
15753 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
15754 return (r && this.selections.key(r.id) ? true : false);
15758 * Returns True if the specified record id is selected.
15759 * @param {String} id The id of record to check
15760 * @return {Boolean}
15762 isIdSelected : function(id){
15763 return (this.selections.key(id) ? true : false);
15767 handleMouseDown : function(e, t){
15768 var view = this.grid.getView(), rowIndex;
15769 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
15772 if(e.shiftKey && this.last !== false){
15773 var last = this.last;
15774 this.selectRange(last, rowIndex, e.ctrlKey);
15775 this.last = last; // reset the last
15776 view.focusRow(rowIndex);
15778 var isSelected = this.isSelected(rowIndex);
15779 if(e.button !== 0 && isSelected){
15780 view.focusRow(rowIndex);
15781 }else if(e.ctrlKey && isSelected){
15782 this.deselectRow(rowIndex);
15783 }else if(!isSelected){
15784 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
15785 view.focusRow(rowIndex);
15788 this.fireEvent("afterselectionchange", this);
15791 handleDragableRowClick : function(grid, rowIndex, e)
15793 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
15794 this.selectRow(rowIndex, false);
15795 grid.view.focusRow(rowIndex);
15796 this.fireEvent("afterselectionchange", this);
15801 * Selects multiple rows.
15802 * @param {Array} rows Array of the indexes of the row to select
15803 * @param {Boolean} keepExisting (optional) True to keep existing selections
15805 selectRows : function(rows, keepExisting){
15807 this.clearSelections();
15809 for(var i = 0, len = rows.length; i < len; i++){
15810 this.selectRow(rows[i], true);
15815 * Selects a range of rows. All rows in between startRow and endRow are also selected.
15816 * @param {Number} startRow The index of the first row in the range
15817 * @param {Number} endRow The index of the last row in the range
15818 * @param {Boolean} keepExisting (optional) True to retain existing selections
15820 selectRange : function(startRow, endRow, keepExisting){
15821 if(this.locked) return;
15823 this.clearSelections();
15825 if(startRow <= endRow){
15826 for(var i = startRow; i <= endRow; i++){
15827 this.selectRow(i, true);
15830 for(var i = startRow; i >= endRow; i--){
15831 this.selectRow(i, true);
15837 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
15838 * @param {Number} startRow The index of the first row in the range
15839 * @param {Number} endRow The index of the last row in the range
15841 deselectRange : function(startRow, endRow, preventViewNotify){
15842 if(this.locked) return;
15843 for(var i = startRow; i <= endRow; i++){
15844 this.deselectRow(i, preventViewNotify);
15850 * @param {Number} row The index of the row to select
15851 * @param {Boolean} keepExisting (optional) True to keep existing selections
15853 selectRow : function(index, keepExisting, preventViewNotify){
15854 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
15855 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
15856 if(!keepExisting || this.singleSelect){
15857 this.clearSelections();
15859 var r = this.grid.dataSource.getAt(index);
15860 this.selections.add(r);
15861 this.last = this.lastActive = index;
15862 if(!preventViewNotify){
15863 this.grid.getView().onRowSelect(index);
15865 this.fireEvent("rowselect", this, index, r);
15866 this.fireEvent("selectionchange", this);
15872 * @param {Number} row The index of the row to deselect
15874 deselectRow : function(index, preventViewNotify){
15875 if(this.locked) return;
15876 if(this.last == index){
15879 if(this.lastActive == index){
15880 this.lastActive = false;
15882 var r = this.grid.dataSource.getAt(index);
15883 this.selections.remove(r);
15884 if(!preventViewNotify){
15885 this.grid.getView().onRowDeselect(index);
15887 this.fireEvent("rowdeselect", this, index);
15888 this.fireEvent("selectionchange", this);
15892 restoreLast : function(){
15894 this.last = this._last;
15899 acceptsNav : function(row, col, cm){
15900 return !cm.isHidden(col) && cm.isCellEditable(col, row);
15904 onEditorKey : function(field, e){
15905 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
15910 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
15912 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
15914 }else if(k == e.ENTER && !e.ctrlKey){
15918 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
15920 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
15922 }else if(k == e.ESC){
15926 g.startEditing(newCell[0], newCell[1]);
15937 * @class Roo.bootstrap.MessageBar
15938 * @extends Roo.bootstrap.Component
15939 * Bootstrap MessageBar class
15940 * @cfg {String} html contents of the MessageBar
15941 * @cfg {String} weight (info | success | warning | danger) default info
15942 * @cfg {String} beforeClass insert the bar before the given class
15943 * @cfg {Boolean} closable (true | false) default false
15944 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
15947 * Create a new Element
15948 * @param {Object} config The config object
15951 Roo.bootstrap.MessageBar = function(config){
15952 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
15955 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
15961 beforeClass: 'bootstrap-sticky-wrap',
15963 getAutoCreate : function(){
15967 cls: 'alert alert-dismissable alert-' + this.weight,
15972 html: this.html || ''
15978 cfg.cls += ' alert-messages-fixed';
15992 onRender : function(ct, position)
15994 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
15997 var cfg = Roo.apply({}, this.getAutoCreate());
16001 cfg.cls += ' ' + this.cls;
16004 cfg.style = this.style;
16006 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
16008 this.el.setVisibilityMode(Roo.Element.DISPLAY);
16011 this.el.select('>button.close').on('click', this.hide, this);
16017 if (!this.rendered) {
16023 this.fireEvent('show', this);
16029 if (!this.rendered) {
16035 this.fireEvent('hide', this);
16038 update : function()
16040 // var e = this.el.dom.firstChild;
16042 // if(this.closable){
16043 // e = e.nextSibling;
16046 // e.data = this.html || '';
16048 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';