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);
2037 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2052 getAutoCreate : function(){
2057 if (this.sidebar === true) {
2065 if (this.bar === true) {
2073 cls: 'navbar-header',
2078 cls: 'navbar-toggle',
2079 'data-toggle': 'collapse',
2084 html: 'Toggle navigation'
2104 cls: 'collapse navbar-collapse'
2109 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
2111 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
2112 cfg.cls += ' navbar-' + this.position;
2113 cfg.tag = this.position == 'fixed-bottom' ? 'footer' : 'header';
2116 if (this.brand !== '') {
2119 href: this.brand_href ? this.brand_href : '#',
2120 cls: 'navbar-brand',
2128 cfg.cls += ' main-nav';
2134 } else if (this.bar === false) {
2137 Roo.log('Property \'bar\' in of Navbar must be either true or false')
2147 if (['tabs','pills'].indexOf(this.type)!==-1) {
2148 cfg.cn[0].cls += ' nav-' + this.type
2150 if (this.type!=='nav') {
2151 Roo.log('nav type must be nav/tabs/pills')
2153 cfg.cn[0].cls += ' navbar-nav'
2156 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
2157 cfg.cn[0].cls += ' nav-' + this.arrangement;
2160 if (this.align === 'right') {
2161 cfg.cn[0].cls += ' navbar-right';
2164 cfg.cls += ' navbar-inverse';
2172 initEvents :function ()
2174 //Roo.log(this.el.select('.navbar-toggle',true));
2175 this.el.select('.navbar-toggle',true).on('click', function() {
2176 // Roo.log('click');
2177 this.el.select('.navbar-collapse',true).toggleClass('in');
2185 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2187 var size = this.el.getSize();
2188 this.maskEl.setSize(size.width, size.height);
2189 this.maskEl.enableDisplayMode("block");
2198 getChildContainer : function()
2200 if (this.bar === true) {
2201 return this.el.select('.collapse',true).first();
2229 * @class Roo.bootstrap.NavGroup
2230 * @extends Roo.bootstrap.Component
2231 * Bootstrap NavGroup class
2232 * @cfg {String} align left | right
2233 * @cfg {Boolean} inverse false | true
2234 * @cfg {String} type (nav|pills|tab) default nav
2237 * Create a new nav group
2238 * @param {Object} config The config object
2241 Roo.bootstrap.NavGroup = function(config){
2242 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
2245 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
2252 getAutoCreate : function(){
2253 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
2260 if (['tabs','pills'].indexOf(this.type)!==-1) {
2261 cfg.cls += ' nav-' + this.type
2263 if (this.type!=='nav') {
2264 Roo.log('nav type must be nav/tabs/pills')
2266 cfg.cls += ' navbar-nav'
2269 if (this.parent().sidebar === true) {
2272 cls: 'dashboard-menu'
2278 if (this.form === true) {
2284 if (this.align === 'right') {
2285 cfg.cls += ' navbar-right';
2287 cfg.cls += ' navbar-left';
2291 if (this.align === 'right') {
2292 cfg.cls += ' navbar-right';
2296 cfg.cls += ' navbar-inverse';
2316 * @class Roo.bootstrap.Navbar.Item
2317 * @extends Roo.bootstrap.Component
2318 * Bootstrap Navbar.Button class
2319 * @cfg {String} href link to
2320 * @cfg {String} html content of button
2321 * @cfg {String} badge text inside badge
2322 * @cfg {String} glyphicon name of glyphicon
2323 * @cfg {String} icon name of font awesome icon
2324 * @cfg {Boolena} active Is item active
2325 * @cfg {Boolean} preventDefault (true | false) default false
2328 * Create a new Navbar Button
2329 * @param {Object} config The config object
2331 Roo.bootstrap.Navbar.Item = function(config){
2332 Roo.bootstrap.Navbar.Item.superclass.constructor.call(this, config);
2337 * The raw click event for the entire grid.
2338 * @param {Roo.EventObject} e
2344 Roo.extend(Roo.bootstrap.Navbar.Item, Roo.bootstrap.Component, {
2353 preventDefault : false,
2355 getAutoCreate : function(){
2357 var cfg = Roo.apply({}, Roo.bootstrap.Navbar.Item.superclass.getAutoCreate.call(this));
2359 if (this.parent().parent().sidebar === true) {
2372 cfg.cn[0].html = this.html;
2376 this.cls += ' active';
2380 cfg.cn[0].cls += ' dropdown-toggle';
2381 cfg.cn[0].html = (cfg.cn[0].html || this.html) + '<span class="glyphicon glyphicon-chevron-down"></span>';
2385 cfg.cn[0].tag = 'a',
2386 cfg.cn[0].href = this.href;
2389 if (this.glyphicon) {
2390 cfg.cn[0].html = '<i class="glyphicon glyphicon-'+this.glyphicon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
2394 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
2406 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
2416 if (this.glyphicon) {
2417 if(cfg.html){cfg.html = ' ' + this.html};
2421 cls: 'glyphicon glyphicon-' + this.glyphicon
2426 cfg.cn[0].html = this.html || cfg.cn[0].html ;
2431 cfg.cn[0].html += " <span class='caret'></span>";
2432 //}else if (!this.href) {
2433 // cfg.cn[0].tag='p';
2434 // cfg.cn[0].cls='navbar-text';
2437 cfg.cn[0].href=this.href||'#';
2438 cfg.cn[0].html=this.html;
2441 if (this.badge !== '') {
2444 cfg.cn[0].html + ' ',
2455 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
2460 initEvents: function() {
2461 // Roo.log('init events?');
2462 // Roo.log(this.el.dom);
2463 this.el.select('a',true).on('click', this.onClick, this);
2466 onClick : function(e)
2468 if(this.preventDefault){
2472 if(this.fireEvent('click', this, e) === false){
2476 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
2477 this.onTabsClick(e);
2481 onTabsClick : function(e)
2483 Roo.each(this.parent().el.select('.active',true).elements, function(v){
2484 v.removeClass('active');
2487 this.el.addClass('active');
2489 if(this.href && this.href.substring(0,1) == '#'){
2490 var tab = Roo.select('[tabId=' + this.href + ']', true).first();
2492 Roo.each(tab.findParent('.tab-content', 0, true).select('.active', true).elements, function(v){
2493 v.removeClass('active');
2496 tab.addClass('active');
2511 * @class Roo.bootstrap.Row
2512 * @extends Roo.bootstrap.Component
2513 * Bootstrap Row class (contains columns...)
2517 * @param {Object} config The config object
2520 Roo.bootstrap.Row = function(config){
2521 Roo.bootstrap.Row.superclass.constructor.call(this, config);
2524 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
2526 getAutoCreate : function(){
2545 * @class Roo.bootstrap.Element
2546 * @extends Roo.bootstrap.Component
2547 * Bootstrap Element class
2548 * @cfg {String} html contents of the element
2549 * @cfg {String} tag tag of the element
2550 * @cfg {String} cls class of the element
2553 * Create a new Element
2554 * @param {Object} config The config object
2557 Roo.bootstrap.Element = function(config){
2558 Roo.bootstrap.Element.superclass.constructor.call(this, config);
2561 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
2568 getAutoCreate : function(){
2593 * @class Roo.bootstrap.Pagination
2594 * @extends Roo.bootstrap.Component
2595 * Bootstrap Pagination class
2596 * @cfg {String} size xs | sm | md | lg
2597 * @cfg {Boolean} inverse false | true
2600 * Create a new Pagination
2601 * @param {Object} config The config object
2604 Roo.bootstrap.Pagination = function(config){
2605 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
2608 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
2614 getAutoCreate : function(){
2620 cfg.cls += ' inverse';
2626 cfg.cls += " " + this.cls;
2644 * @class Roo.bootstrap.PaginationItem
2645 * @extends Roo.bootstrap.Component
2646 * Bootstrap PaginationItem class
2647 * @cfg {String} html text
2648 * @cfg {String} href the link
2649 * @cfg {Boolean} preventDefault (true | false) default true
2650 * @cfg {Boolean} active (true | false) default false
2654 * Create a new PaginationItem
2655 * @param {Object} config The config object
2659 Roo.bootstrap.PaginationItem = function(config){
2660 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
2665 * The raw click event for the entire grid.
2666 * @param {Roo.EventObject} e
2672 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
2676 preventDefault: true,
2680 getAutoCreate : function(){
2686 href : this.href ? this.href : '#',
2687 html : this.html ? this.html : ''
2697 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
2703 initEvents: function() {
2705 this.el.on('click', this.onClick, this);
2708 onClick : function(e)
2710 Roo.log('PaginationItem on click ');
2711 if(this.preventDefault){
2715 this.fireEvent('click', this, e);
2731 * @class Roo.bootstrap.Slider
2732 * @extends Roo.bootstrap.Component
2733 * Bootstrap Slider class
2736 * Create a new Slider
2737 * @param {Object} config The config object
2740 Roo.bootstrap.Slider = function(config){
2741 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
2744 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
2746 getAutoCreate : function(){
2750 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
2754 cls: 'ui-slider-handle ui-state-default ui-corner-all'
2772 * @class Roo.bootstrap.Table
2773 * @extends Roo.bootstrap.Component
2774 * Bootstrap Table class
2775 * @cfg {String} cls table class
2776 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
2777 * @cfg {String} bgcolor Specifies the background color for a table
2778 * @cfg {Number} border Specifies whether the table cells should have borders or not
2779 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
2780 * @cfg {Number} cellspacing Specifies the space between cells
2781 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
2782 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
2783 * @cfg {String} sortable Specifies that the table should be sortable
2784 * @cfg {String} summary Specifies a summary of the content of a table
2785 * @cfg {Number} width Specifies the width of a table
2787 * @cfg {boolean} striped Should the rows be alternative striped
2788 * @cfg {boolean} bordered Add borders to the table
2789 * @cfg {boolean} hover Add hover highlighting
2790 * @cfg {boolean} condensed Format condensed
2791 * @cfg {boolean} responsive Format condensed
2797 * Create a new Table
2798 * @param {Object} config The config object
2801 Roo.bootstrap.Table = function(config){
2802 Roo.bootstrap.Table.superclass.constructor.call(this, config);
2805 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
2806 this.sm = this.selModel;
2807 this.sm.xmodule = this.xmodule || false;
2809 if (this.cm && typeof(this.cm.config) == 'undefined') {
2810 this.colModel = new Roo.bootstrap.Table.ColumnModel(this.cm);
2811 this.cm = this.colModel;
2812 this.cm.xmodule = this.xmodule || false;
2815 this.store= Roo.factory(this.store, Roo.data);
2816 this.ds = this.store;
2817 this.ds.xmodule = this.xmodule || false;
2822 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
2844 getAutoCreate : function(){
2845 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
2854 cfg.cls += ' table-striped';
2857 cfg.cls += ' table-hover';
2859 if (this.bordered) {
2860 cfg.cls += ' table-bordered';
2862 if (this.condensed) {
2863 cfg.cls += ' table-condensed';
2865 if (this.responsive) {
2866 cfg.cls += ' table-responsive';
2873 cfg.cls+= ' ' +this.cls;
2876 // this lot should be simplifed...
2879 cfg.align=this.align;
2882 cfg.bgcolor=this.bgcolor;
2885 cfg.border=this.border;
2887 if (this.cellpadding) {
2888 cfg.cellpadding=this.cellpadding;
2890 if (this.cellspacing) {
2891 cfg.cellspacing=this.cellspacing;
2894 cfg.frame=this.frame;
2897 cfg.rules=this.rules;
2899 if (this.sortable) {
2900 cfg.sortable=this.sortable;
2903 cfg.summary=this.summary;
2906 cfg.width=this.width;
2909 if(this.store || this.cm){
2910 cfg.cn.push(this.renderHeader());
2911 cfg.cn.push(this.renderBody());
2912 cfg.cn.push(this.renderFooter());
2914 cfg.cls+= ' TableGrid';
2920 // initTableGrid : function()
2929 // var cm = this.cm;
2931 // for(var i = 0, len = cm.getColumnCount(); i < len; i++){
2934 // html: cm.getColumnHeader(i)
2938 // cfg.push(header);
2945 initEvents : function()
2947 if(!this.store || !this.cm){
2951 Roo.log('initEvents with ds!!!!');
2953 // this.maskEl = Roo.DomHelper.append(this.el.select('.TableGrid', true).first(), {tag: "div", cls:"x-dlg-mask"}, true);
2954 // this.maskEl.enableDisplayMode("block");
2955 // this.maskEl.show();
2957 this.store.on('load', this.onLoad, this);
2958 this.store.on('beforeload', this.onBeforeLoad, this);
2966 renderHeader : function()
2975 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
2978 html: cm.getColumnHeader(i)
2985 renderBody : function()
2995 renderFooter : function()
3007 Roo.log('ds onload');
3011 var tbody = this.el.select('tbody', true).first();
3015 if(this.store.getCount() > 0){
3016 this.store.data.each(function(d){
3022 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
3023 var renderer = cm.getRenderer(i);
3027 if(typeof(renderer) !== 'undefined'){
3028 value = renderer(d.data[cm.getDataIndex(i)], false, d);
3031 if(typeof(value) === 'object'){
3041 html: (typeof(value) === 'object') ? '' : value
3046 tbody.createChild(row);
3054 Roo.each(renders, function(r){
3055 _this.renderColumn(r);
3059 // if(this.loadMask){
3060 // this.maskEl.hide();
3064 onBeforeLoad : function()
3066 Roo.log('ds onBeforeLoad');
3070 // if(this.loadMask){
3071 // this.maskEl.show();
3077 this.el.select('tbody', true).first().dom.innerHTML = '';
3080 getSelectionModel : function(){
3082 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
3084 return this.selModel;
3087 renderColumn : function(r)
3090 r.cfg.render(Roo.get(r.id));
3093 Roo.each(r.cfg.cn, function(c){
3098 _this.renderColumn(child);
3115 * @class Roo.bootstrap.TableCell
3116 * @extends Roo.bootstrap.Component
3117 * Bootstrap TableCell class
3118 * @cfg {String} html cell contain text
3119 * @cfg {String} cls cell class
3120 * @cfg {String} tag cell tag (td|th) default td
3121 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
3122 * @cfg {String} align Aligns the content in a cell
3123 * @cfg {String} axis Categorizes cells
3124 * @cfg {String} bgcolor Specifies the background color of a cell
3125 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
3126 * @cfg {Number} colspan Specifies the number of columns a cell should span
3127 * @cfg {String} headers Specifies one or more header cells a cell is related to
3128 * @cfg {Number} height Sets the height of a cell
3129 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
3130 * @cfg {Number} rowspan Sets the number of rows a cell should span
3131 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
3132 * @cfg {String} valign Vertical aligns the content in a cell
3133 * @cfg {Number} width Specifies the width of a cell
3136 * Create a new TableCell
3137 * @param {Object} config The config object
3140 Roo.bootstrap.TableCell = function(config){
3141 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
3144 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
3164 getAutoCreate : function(){
3165 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
3185 cfg.align=this.align
3191 cfg.bgcolor=this.bgcolor
3194 cfg.charoff=this.charoff
3197 cfg.colspan=this.colspan
3200 cfg.headers=this.headers
3203 cfg.height=this.height
3206 cfg.nowrap=this.nowrap
3209 cfg.rowspan=this.rowspan
3212 cfg.scope=this.scope
3215 cfg.valign=this.valign
3218 cfg.width=this.width
3237 * @class Roo.bootstrap.TableRow
3238 * @extends Roo.bootstrap.Component
3239 * Bootstrap TableRow class
3240 * @cfg {String} cls row class
3241 * @cfg {String} align Aligns the content in a table row
3242 * @cfg {String} bgcolor Specifies a background color for a table row
3243 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
3244 * @cfg {String} valign Vertical aligns the content in a table row
3247 * Create a new TableRow
3248 * @param {Object} config The config object
3251 Roo.bootstrap.TableRow = function(config){
3252 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
3255 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
3263 getAutoCreate : function(){
3264 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
3274 cfg.align = this.align;
3277 cfg.bgcolor = this.bgcolor;
3280 cfg.charoff = this.charoff;
3283 cfg.valign = this.valign;
3301 * @class Roo.bootstrap.TableBody
3302 * @extends Roo.bootstrap.Component
3303 * Bootstrap TableBody class
3304 * @cfg {String} cls element class
3305 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
3306 * @cfg {String} align Aligns the content inside the element
3307 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
3308 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
3311 * Create a new TableBody
3312 * @param {Object} config The config object
3315 Roo.bootstrap.TableBody = function(config){
3316 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
3319 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
3327 getAutoCreate : function(){
3328 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
3342 cfg.align = this.align;
3345 cfg.charoff = this.charoff;
3348 cfg.valign = this.valign;
3355 // initEvents : function()
3362 // this.store = Roo.factory(this.store, Roo.data);
3363 // this.store.on('load', this.onLoad, this);
3365 // this.store.load();
3369 // onLoad: function ()
3371 // this.fireEvent('load', this);
3381 * Ext JS Library 1.1.1
3382 * Copyright(c) 2006-2007, Ext JS, LLC.
3384 * Originally Released Under LGPL - original licence link has changed is not relivant.
3387 * <script type="text/javascript">
3390 // as we use this in bootstrap.
3391 Roo.namespace('Roo.form');
3393 * @class Roo.form.Action
3394 * Internal Class used to handle form actions
3396 * @param {Roo.form.BasicForm} el The form element or its id
3397 * @param {Object} config Configuration options
3402 // define the action interface
3403 Roo.form.Action = function(form, options){
3405 this.options = options || {};
3408 * Client Validation Failed
3411 Roo.form.Action.CLIENT_INVALID = 'client';
3413 * Server Validation Failed
3416 Roo.form.Action.SERVER_INVALID = 'server';
3418 * Connect to Server Failed
3421 Roo.form.Action.CONNECT_FAILURE = 'connect';
3423 * Reading Data from Server Failed
3426 Roo.form.Action.LOAD_FAILURE = 'load';
3428 Roo.form.Action.prototype = {
3430 failureType : undefined,
3431 response : undefined,
3435 run : function(options){
3440 success : function(response){
3445 handleResponse : function(response){
3449 // default connection failure
3450 failure : function(response){
3452 this.response = response;
3453 this.failureType = Roo.form.Action.CONNECT_FAILURE;
3454 this.form.afterAction(this, false);
3457 processResponse : function(response){
3458 this.response = response;
3459 if(!response.responseText){
3462 this.result = this.handleResponse(response);
3466 // utility functions used internally
3467 getUrl : function(appendParams){
3468 var url = this.options.url || this.form.url || this.form.el.dom.action;
3470 var p = this.getParams();
3472 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
3478 getMethod : function(){
3479 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
3482 getParams : function(){
3483 var bp = this.form.baseParams;
3484 var p = this.options.params;
3486 if(typeof p == "object"){
3487 p = Roo.urlEncode(Roo.applyIf(p, bp));
3488 }else if(typeof p == 'string' && bp){
3489 p += '&' + Roo.urlEncode(bp);
3492 p = Roo.urlEncode(bp);
3497 createCallback : function(){
3499 success: this.success,
3500 failure: this.failure,
3502 timeout: (this.form.timeout*1000),
3503 upload: this.form.fileUpload ? this.success : undefined
3508 Roo.form.Action.Submit = function(form, options){
3509 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
3512 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
3515 haveProgress : false,
3516 uploadComplete : false,
3518 // uploadProgress indicator.
3519 uploadProgress : function()
3521 if (!this.form.progressUrl) {
3525 if (!this.haveProgress) {
3526 Roo.MessageBox.progress("Uploading", "Uploading");
3528 if (this.uploadComplete) {
3529 Roo.MessageBox.hide();
3533 this.haveProgress = true;
3535 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
3537 var c = new Roo.data.Connection();
3539 url : this.form.progressUrl,
3544 success : function(req){
3545 //console.log(data);
3549 rdata = Roo.decode(req.responseText)
3551 Roo.log("Invalid data from server..");
3555 if (!rdata || !rdata.success) {
3557 Roo.MessageBox.alert(Roo.encode(rdata));
3560 var data = rdata.data;
3562 if (this.uploadComplete) {
3563 Roo.MessageBox.hide();
3568 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
3569 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
3572 this.uploadProgress.defer(2000,this);
3575 failure: function(data) {
3576 Roo.log('progress url failed ');
3587 // run get Values on the form, so it syncs any secondary forms.
3588 this.form.getValues();
3590 var o = this.options;
3591 var method = this.getMethod();
3592 var isPost = method == 'POST';
3593 if(o.clientValidation === false || this.form.isValid()){
3595 if (this.form.progressUrl) {
3596 this.form.findField('UPLOAD_IDENTIFIER').setValue(
3597 (new Date() * 1) + '' + Math.random());
3602 Roo.Ajax.request(Roo.apply(this.createCallback(), {
3603 form:this.form.el.dom,
3604 url:this.getUrl(!isPost),
3606 params:isPost ? this.getParams() : null,
3607 isUpload: this.form.fileUpload
3610 this.uploadProgress();
3612 }else if (o.clientValidation !== false){ // client validation failed
3613 this.failureType = Roo.form.Action.CLIENT_INVALID;
3614 this.form.afterAction(this, false);
3618 success : function(response)
3620 this.uploadComplete= true;
3621 if (this.haveProgress) {
3622 Roo.MessageBox.hide();
3626 var result = this.processResponse(response);
3627 if(result === true || result.success){
3628 this.form.afterAction(this, true);
3632 this.form.markInvalid(result.errors);
3633 this.failureType = Roo.form.Action.SERVER_INVALID;
3635 this.form.afterAction(this, false);
3637 failure : function(response)
3639 this.uploadComplete= true;
3640 if (this.haveProgress) {
3641 Roo.MessageBox.hide();
3644 this.response = response;
3645 this.failureType = Roo.form.Action.CONNECT_FAILURE;
3646 this.form.afterAction(this, false);
3649 handleResponse : function(response){
3650 if(this.form.errorReader){
3651 var rs = this.form.errorReader.read(response);
3654 for(var i = 0, len = rs.records.length; i < len; i++) {
3655 var r = rs.records[i];
3659 if(errors.length < 1){
3663 success : rs.success,
3669 ret = Roo.decode(response.responseText);
3673 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
3683 Roo.form.Action.Load = function(form, options){
3684 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
3685 this.reader = this.form.reader;
3688 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
3693 Roo.Ajax.request(Roo.apply(
3694 this.createCallback(), {
3695 method:this.getMethod(),
3696 url:this.getUrl(false),
3697 params:this.getParams()
3701 success : function(response){
3703 var result = this.processResponse(response);
3704 if(result === true || !result.success || !result.data){
3705 this.failureType = Roo.form.Action.LOAD_FAILURE;
3706 this.form.afterAction(this, false);
3709 this.form.clearInvalid();
3710 this.form.setValues(result.data);
3711 this.form.afterAction(this, true);
3714 handleResponse : function(response){
3715 if(this.form.reader){
3716 var rs = this.form.reader.read(response);
3717 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
3719 success : rs.success,
3723 return Roo.decode(response.responseText);
3727 Roo.form.Action.ACTION_TYPES = {
3728 'load' : Roo.form.Action.Load,
3729 'submit' : Roo.form.Action.Submit
3738 * @class Roo.bootstrap.Form
3739 * @extends Roo.bootstrap.Component
3740 * Bootstrap Form class
3741 * @cfg {String} method GET | POST (default POST)
3742 * @cfg {String} labelAlign top | left (default top)
3743 * @cfg {String} align left | right - for navbars
3748 * @param {Object} config The config object
3752 Roo.bootstrap.Form = function(config){
3753 Roo.bootstrap.Form.superclass.constructor.call(this, config);
3756 * @event clientvalidation
3757 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
3758 * @param {Form} this
3759 * @param {Boolean} valid true if the form has passed client-side validation
3761 clientvalidation: true,
3763 * @event beforeaction
3764 * Fires before any action is performed. Return false to cancel the action.
3765 * @param {Form} this
3766 * @param {Action} action The action to be performed
3770 * @event actionfailed
3771 * Fires when an action fails.
3772 * @param {Form} this
3773 * @param {Action} action The action that failed
3775 actionfailed : true,
3777 * @event actioncomplete
3778 * Fires when an action is completed.
3779 * @param {Form} this
3780 * @param {Action} action The action that completed
3782 actioncomplete : true
3787 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
3790 * @cfg {String} method
3791 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
3796 * The URL to use for form actions if one isn't supplied in the action options.
3799 * @cfg {Boolean} fileUpload
3800 * Set to true if this form is a file upload.
3804 * @cfg {Object} baseParams
3805 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
3809 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
3813 * @cfg {Sting} align (left|right) for navbar forms
3818 activeAction : null,
3821 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
3822 * element by passing it or its id or mask the form itself by passing in true.
3825 waitMsgTarget : false,
3830 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
3831 * element by passing it or its id or mask the form itself by passing in true.
3835 getAutoCreate : function(){
3839 method : this.method || 'POST',
3840 id : this.id || Roo.id(),
3843 if (this.parent().xtype.match(/^Nav/)) {
3844 cfg.cls = 'navbar-form navbar-' + this.align;
3848 if (this.labelAlign == 'left' ) {
3849 cfg.cls += ' form-horizontal';
3855 initEvents : function()
3857 this.el.on('submit', this.onSubmit, this);
3862 onSubmit : function(e){
3867 * Returns true if client-side validation on the form is successful.
3870 isValid : function(){
3871 var items = this.getItems();
3873 items.each(function(f){
3882 * Returns true if any fields in this form have changed since their original load.
3885 isDirty : function(){
3887 var items = this.getItems();
3888 items.each(function(f){
3898 * Performs a predefined action (submit or load) or custom actions you define on this form.
3899 * @param {String} actionName The name of the action type
3900 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
3901 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
3902 * accept other config options):
3904 Property Type Description
3905 ---------------- --------------- ----------------------------------------------------------------------------------
3906 url String The url for the action (defaults to the form's url)
3907 method String The form method to use (defaults to the form's method, or POST if not defined)
3908 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
3909 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
3910 validate the form on the client (defaults to false)
3912 * @return {BasicForm} this
3914 doAction : function(action, options){
3915 if(typeof action == 'string'){
3916 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
3918 if(this.fireEvent('beforeaction', this, action) !== false){
3919 this.beforeAction(action);
3920 action.run.defer(100, action);
3926 beforeAction : function(action){
3927 var o = action.options;
3929 // not really supported yet.. ??
3931 //if(this.waitMsgTarget === true){
3932 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
3933 //}else if(this.waitMsgTarget){
3934 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
3935 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
3937 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
3943 afterAction : function(action, success){
3944 this.activeAction = null;
3945 var o = action.options;
3947 //if(this.waitMsgTarget === true){
3949 //}else if(this.waitMsgTarget){
3950 // this.waitMsgTarget.unmask();
3952 // Roo.MessageBox.updateProgress(1);
3953 // Roo.MessageBox.hide();
3960 Roo.callback(o.success, o.scope, [this, action]);
3961 this.fireEvent('actioncomplete', this, action);
3965 // failure condition..
3966 // we have a scenario where updates need confirming.
3967 // eg. if a locking scenario exists..
3968 // we look for { errors : { needs_confirm : true }} in the response.
3970 (typeof(action.result) != 'undefined') &&
3971 (typeof(action.result.errors) != 'undefined') &&
3972 (typeof(action.result.errors.needs_confirm) != 'undefined')
3975 Roo.log("not supported yet");
3978 Roo.MessageBox.confirm(
3979 "Change requires confirmation",
3980 action.result.errorMsg,
3985 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
3995 Roo.callback(o.failure, o.scope, [this, action]);
3996 // show an error message if no failed handler is set..
3997 if (!this.hasListener('actionfailed')) {
3998 Roo.log("need to add dialog support");
4000 Roo.MessageBox.alert("Error",
4001 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
4002 action.result.errorMsg :
4003 "Saving Failed, please check your entries or try again"
4008 this.fireEvent('actionfailed', this, action);
4013 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
4014 * @param {String} id The value to search for
4017 findField : function(id){
4018 var items = this.getItems();
4019 var field = items.get(id);
4021 items.each(function(f){
4022 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
4029 return field || null;
4032 * Mark fields in this form invalid in bulk.
4033 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
4034 * @return {BasicForm} this
4036 markInvalid : function(errors){
4037 if(errors instanceof Array){
4038 for(var i = 0, len = errors.length; i < len; i++){
4039 var fieldError = errors[i];
4040 var f = this.findField(fieldError.id);
4042 f.markInvalid(fieldError.msg);
4048 if(typeof errors[id] != 'function' && (field = this.findField(id))){
4049 field.markInvalid(errors[id]);
4053 //Roo.each(this.childForms || [], function (f) {
4054 // f.markInvalid(errors);
4061 * Set values for fields in this form in bulk.
4062 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
4063 * @return {BasicForm} this
4065 setValues : function(values){
4066 if(values instanceof Array){ // array of objects
4067 for(var i = 0, len = values.length; i < len; i++){
4069 var f = this.findField(v.id);
4071 f.setValue(v.value);
4072 if(this.trackResetOnLoad){
4073 f.originalValue = f.getValue();
4077 }else{ // object hash
4080 if(typeof values[id] != 'function' && (field = this.findField(id))){
4082 if (field.setFromData &&
4084 field.displayField &&
4085 // combos' with local stores can
4086 // be queried via setValue()
4087 // to set their value..
4088 (field.store && !field.store.isLocal)
4092 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
4093 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
4094 field.setFromData(sd);
4097 field.setValue(values[id]);
4101 if(this.trackResetOnLoad){
4102 field.originalValue = field.getValue();
4108 //Roo.each(this.childForms || [], function (f) {
4109 // f.setValues(values);
4116 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
4117 * they are returned as an array.
4118 * @param {Boolean} asString
4121 getValues : function(asString){
4122 //if (this.childForms) {
4123 // copy values from the child forms
4124 // Roo.each(this.childForms, function (f) {
4125 // this.setValues(f.getValues());
4131 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
4132 if(asString === true){
4135 return Roo.urlDecode(fs);
4139 * Returns the fields in this form as an object with key/value pairs.
4140 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
4143 getFieldValues : function(with_hidden)
4145 var items = this.getItems();
4147 items.each(function(f){
4151 var v = f.getValue();
4152 if (f.inputType =='radio') {
4153 if (typeof(ret[f.getName()]) == 'undefined') {
4154 ret[f.getName()] = ''; // empty..
4157 if (!f.el.dom.checked) {
4165 // not sure if this supported any more..
4166 if ((typeof(v) == 'object') && f.getRawValue) {
4167 v = f.getRawValue() ; // dates..
4169 // combo boxes where name != hiddenName...
4170 if (f.name != f.getName()) {
4171 ret[f.name] = f.getRawValue();
4173 ret[f.getName()] = v;
4180 * Clears all invalid messages in this form.
4181 * @return {BasicForm} this
4183 clearInvalid : function(){
4184 var items = this.getItems();
4186 items.each(function(f){
4197 * @return {BasicForm} this
4200 var items = this.getItems();
4201 items.each(function(f){
4205 Roo.each(this.childForms || [], function (f) {
4212 getItems : function()
4214 var r=new Roo.util.MixedCollection(false, function(o){
4215 return o.id || (o.id = Roo.id());
4217 var iter = function(el) {
4224 Roo.each(el.items,function(e) {
4243 * Ext JS Library 1.1.1
4244 * Copyright(c) 2006-2007, Ext JS, LLC.
4246 * Originally Released Under LGPL - original licence link has changed is not relivant.
4249 * <script type="text/javascript">
4252 * @class Roo.form.VTypes
4253 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
4256 Roo.form.VTypes = function(){
4257 // closure these in so they are only created once.
4258 var alpha = /^[a-zA-Z_]+$/;
4259 var alphanum = /^[a-zA-Z0-9_]+$/;
4260 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
4261 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
4263 // All these messages and functions are configurable
4266 * The function used to validate email addresses
4267 * @param {String} value The email address
4269 'email' : function(v){
4270 return email.test(v);
4273 * The error text to display when the email validation function returns false
4276 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
4278 * The keystroke filter mask to be applied on email input
4281 'emailMask' : /[a-z0-9_\.\-@]/i,
4284 * The function used to validate URLs
4285 * @param {String} value The URL
4287 'url' : function(v){
4291 * The error text to display when the url validation function returns false
4294 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
4297 * The function used to validate alpha values
4298 * @param {String} value The value
4300 'alpha' : function(v){
4301 return alpha.test(v);
4304 * The error text to display when the alpha validation function returns false
4307 'alphaText' : 'This field should only contain letters and _',
4309 * The keystroke filter mask to be applied on alpha input
4312 'alphaMask' : /[a-z_]/i,
4315 * The function used to validate alphanumeric values
4316 * @param {String} value The value
4318 'alphanum' : function(v){
4319 return alphanum.test(v);
4322 * The error text to display when the alphanumeric validation function returns false
4325 'alphanumText' : 'This field should only contain letters, numbers and _',
4327 * The keystroke filter mask to be applied on alphanumeric input
4330 'alphanumMask' : /[a-z0-9_]/i
4340 * @class Roo.bootstrap.Input
4341 * @extends Roo.bootstrap.Component
4342 * Bootstrap Input class
4343 * @cfg {Boolean} disabled is it disabled
4344 * @cfg {String} fieldLabel - the label associated
4345 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
4346 * @cfg {String} name name of the input
4347 * @cfg {string} fieldLabel - the label associated
4348 * @cfg {string} inputType - input / file submit ...
4349 * @cfg {string} placeholder - placeholder to put in text.
4350 * @cfg {string} before - input group add on before
4351 * @cfg {string} after - input group add on after
4352 * @cfg {string} size - (lg|sm) or leave empty..
4353 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
4354 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
4355 * @cfg {Number} md colspan out of 12 for computer-sized screens
4356 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
4357 * @cfg {string} value default value of the input
4358 * @cfg {Number} labelWidth set the width of label (0-12)
4359 * @cfg {String} labelAlign (top|left)
4360 * @cfg {Boolean} readOnly Specifies that the field should be read-only
4364 * Create a new Input
4365 * @param {Object} config The config object
4368 Roo.bootstrap.Input = function(config){
4369 Roo.bootstrap.Input.superclass.constructor.call(this, config);
4374 * Fires when this field receives input focus.
4375 * @param {Roo.form.Field} this
4380 * Fires when this field loses input focus.
4381 * @param {Roo.form.Field} this
4386 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
4387 * {@link Roo.EventObject#getKey} to determine which key was pressed.
4388 * @param {Roo.form.Field} this
4389 * @param {Roo.EventObject} e The event object
4394 * Fires just before the field blurs if the field value has changed.
4395 * @param {Roo.form.Field} this
4396 * @param {Mixed} newValue The new value
4397 * @param {Mixed} oldValue The original value
4402 * Fires after the field has been marked as invalid.
4403 * @param {Roo.form.Field} this
4404 * @param {String} msg The validation message
4409 * Fires after the field has been validated with no errors.
4410 * @param {Roo.form.Field} this
4415 * Fires after the key up
4416 * @param {Roo.form.Field} this
4417 * @param {Roo.EventObject} e The event Object
4423 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
4425 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
4426 automatic validation (defaults to "keyup").
4428 validationEvent : "keyup",
4430 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
4432 validateOnBlur : true,
4434 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
4436 validationDelay : 250,
4438 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
4440 focusClass : "x-form-focus", // not needed???
4444 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
4446 invalidClass : "has-error",
4449 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
4451 selectOnFocus : false,
4454 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
4458 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
4463 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
4465 disableKeyFilter : false,
4468 * @cfg {Boolean} disabled True to disable the field (defaults to false).
4472 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
4476 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
4478 blankText : "This field is required",
4481 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
4485 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
4487 maxLength : Number.MAX_VALUE,
4489 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
4491 minLengthText : "The minimum length for this field is {0}",
4493 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
4495 maxLengthText : "The maximum length for this field is {0}",
4499 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
4500 * If available, this function will be called only after the basic validators all return true, and will be passed the
4501 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
4505 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
4506 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
4507 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
4511 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
4534 parentLabelAlign : function()
4537 while (parent.parent()) {
4538 parent = parent.parent();
4539 if (typeof(parent.labelAlign) !='undefined') {
4540 return parent.labelAlign;
4547 getAutoCreate : function(){
4549 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
4555 if(this.inputType != 'hidden'){
4556 cfg.cls = 'form-group' //input-group
4562 type : this.inputType,
4564 cls : 'form-control',
4565 placeholder : this.placeholder || ''
4569 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
4570 input.maxLength = this.maxLength;
4573 if (this.disabled) {
4574 input.disabled=true;
4577 if (this.readOnly) {
4578 input.readonly=true;
4582 input.name = this.name;
4585 input.cls += ' input-' + this.size;
4588 ['xs','sm','md','lg'].map(function(size){
4589 if (settings[size]) {
4590 cfg.cls += ' col-' + size + '-' + settings[size];
4594 var inputblock = input;
4596 if (this.before || this.after) {
4599 cls : 'input-group',
4603 inputblock.cn.push({
4605 cls : 'input-group-addon',
4609 inputblock.cn.push(input);
4611 inputblock.cn.push({
4613 cls : 'input-group-addon',
4620 if (align ==='left' && this.fieldLabel.length) {
4621 Roo.log("left and has label");
4627 cls : 'control-label col-sm-' + this.labelWidth,
4628 html : this.fieldLabel
4632 cls : "col-sm-" + (12 - this.labelWidth),
4639 } else if ( this.fieldLabel.length) {
4645 //cls : 'input-group-addon',
4646 html : this.fieldLabel
4656 Roo.log(" no label && no align");
4665 Roo.log('input-parentType: ' + this.parentType);
4667 if (this.parentType === 'Navbar' && this.parent().bar) {
4668 cfg.cls += ' navbar-form';
4676 * return the real input element.
4678 inputEl: function ()
4680 return this.el.select('input.form-control',true).first();
4682 setDisabled : function(v)
4684 var i = this.inputEl().dom;
4686 i.removeAttribute('disabled');
4690 i.setAttribute('disabled','true');
4692 initEvents : function()
4695 this.inputEl().on("keydown" , this.fireKey, this);
4696 this.inputEl().on("focus", this.onFocus, this);
4697 this.inputEl().on("blur", this.onBlur, this);
4699 this.inputEl().relayEvent('keyup', this);
4701 // reference to original value for reset
4702 this.originalValue = this.getValue();
4703 //Roo.form.TextField.superclass.initEvents.call(this);
4704 if(this.validationEvent == 'keyup'){
4705 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
4706 this.inputEl().on('keyup', this.filterValidation, this);
4708 else if(this.validationEvent !== false){
4709 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
4712 if(this.selectOnFocus){
4713 this.on("focus", this.preFocus, this);
4716 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
4717 this.inputEl().on("keypress", this.filterKeys, this);
4720 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
4721 this.el.on("click", this.autoSize, this);
4724 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
4725 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
4729 filterValidation : function(e){
4730 if(!e.isNavKeyPress()){
4731 this.validationTask.delay(this.validationDelay);
4735 * Validates the field value
4736 * @return {Boolean} True if the value is valid, else false
4738 validate : function(){
4739 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
4740 if(this.disabled || this.validateValue(this.getRawValue())){
4741 this.clearInvalid();
4749 * Validates a value according to the field's validation rules and marks the field as invalid
4750 * if the validation fails
4751 * @param {Mixed} value The value to validate
4752 * @return {Boolean} True if the value is valid, else false
4754 validateValue : function(value){
4755 if(value.length < 1) { // if it's blank
4756 if(this.allowBlank){
4757 this.clearInvalid();
4760 this.markInvalid(this.blankText);
4764 if(value.length < this.minLength){
4765 this.markInvalid(String.format(this.minLengthText, this.minLength));
4768 if(value.length > this.maxLength){
4769 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
4773 var vt = Roo.form.VTypes;
4774 if(!vt[this.vtype](value, this)){
4775 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
4779 if(typeof this.validator == "function"){
4780 var msg = this.validator(value);
4782 this.markInvalid(msg);
4786 if(this.regex && !this.regex.test(value)){
4787 this.markInvalid(this.regexText);
4796 fireKey : function(e){
4797 //Roo.log('field ' + e.getKey());
4798 if(e.isNavKeyPress()){
4799 this.fireEvent("specialkey", this, e);
4802 focus : function (selectText){
4804 this.inputEl().focus();
4805 if(selectText === true){
4806 this.inputEl().dom.select();
4812 onFocus : function(){
4813 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
4814 // this.el.addClass(this.focusClass);
4817 this.hasFocus = true;
4818 this.startValue = this.getValue();
4819 this.fireEvent("focus", this);
4823 beforeBlur : Roo.emptyFn,
4827 onBlur : function(){
4829 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
4830 //this.el.removeClass(this.focusClass);
4832 this.hasFocus = false;
4833 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
4836 var v = this.getValue();
4837 if(String(v) !== String(this.startValue)){
4838 this.fireEvent('change', this, v, this.startValue);
4840 this.fireEvent("blur", this);
4844 * Resets the current field value to the originally loaded value and clears any validation messages
4847 this.setValue(this.originalValue);
4848 this.clearInvalid();
4851 * Returns the name of the field
4852 * @return {Mixed} name The name field
4854 getName: function(){
4858 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
4859 * @return {Mixed} value The field value
4861 getValue : function(){
4862 return this.inputEl().getValue();
4865 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
4866 * @return {Mixed} value The field value
4868 getRawValue : function(){
4869 var v = this.inputEl().getValue();
4875 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
4876 * @param {Mixed} value The value to set
4878 setRawValue : function(v){
4879 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
4882 selectText : function(start, end){
4883 var v = this.getRawValue();
4885 start = start === undefined ? 0 : start;
4886 end = end === undefined ? v.length : end;
4887 var d = this.inputEl().dom;
4888 if(d.setSelectionRange){
4889 d.setSelectionRange(start, end);
4890 }else if(d.createTextRange){
4891 var range = d.createTextRange();
4892 range.moveStart("character", start);
4893 range.moveEnd("character", v.length-end);
4900 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
4901 * @param {Mixed} value The value to set
4903 setValue : function(v){
4906 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
4912 processValue : function(value){
4913 if(this.stripCharsRe){
4914 var newValue = value.replace(this.stripCharsRe, '');
4915 if(newValue !== value){
4916 this.setRawValue(newValue);
4923 preFocus : function(){
4925 if(this.selectOnFocus){
4926 this.inputEl().dom.select();
4929 filterKeys : function(e){
4931 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
4934 var c = e.getCharCode(), cc = String.fromCharCode(c);
4935 if(Roo.isIE && (e.isSpecialKey() || !cc)){
4938 if(!this.maskRe.test(cc)){
4943 * Clear any invalid styles/messages for this field
4945 clearInvalid : function(){
4947 if(!this.el || this.preventMark){ // not rendered
4950 this.el.removeClass(this.invalidClass);
4952 switch(this.msgTarget){
4954 this.el.dom.qtip = '';
4957 this.el.dom.title = '';
4961 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
4966 this.errorIcon.dom.qtip = '';
4967 this.errorIcon.hide();
4968 this.un('resize', this.alignErrorIcon, this);
4972 var t = Roo.getDom(this.msgTarget);
4974 t.style.display = 'none';
4978 this.fireEvent('valid', this);
4981 * Mark this field as invalid
4982 * @param {String} msg The validation message
4984 markInvalid : function(msg){
4985 if(!this.el || this.preventMark){ // not rendered
4988 this.el.addClass(this.invalidClass);
4990 msg = msg || this.invalidText;
4991 switch(this.msgTarget){
4993 this.el.dom.qtip = msg;
4994 this.el.dom.qclass = 'x-form-invalid-tip';
4995 if(Roo.QuickTips){ // fix for floating editors interacting with DND
4996 Roo.QuickTips.enable();
5000 this.el.dom.title = msg;
5004 var elp = this.el.findParent('.x-form-element', 5, true);
5005 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
5006 this.errorEl.setWidth(elp.getWidth(true)-20);
5008 this.errorEl.update(msg);
5009 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
5012 if(!this.errorIcon){
5013 var elp = this.el.findParent('.x-form-element', 5, true);
5014 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
5016 this.alignErrorIcon();
5017 this.errorIcon.dom.qtip = msg;
5018 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
5019 this.errorIcon.show();
5020 this.on('resize', this.alignErrorIcon, this);
5023 var t = Roo.getDom(this.msgTarget);
5025 t.style.display = this.msgDisplay;
5029 this.fireEvent('invalid', this, msg);
5032 SafariOnKeyDown : function(event)
5034 // this is a workaround for a password hang bug on chrome/ webkit.
5036 var isSelectAll = false;
5038 if(this.inputEl().dom.selectionEnd > 0){
5039 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
5041 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
5042 event.preventDefault();
5047 if(isSelectAll){ // backspace and delete key
5049 event.preventDefault();
5050 // this is very hacky as keydown always get's upper case.
5052 var cc = String.fromCharCode(event.getCharCode());
5053 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
5057 adjustWidth : function(tag, w){
5058 tag = tag.toLowerCase();
5059 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
5060 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
5064 if(tag == 'textarea'){
5067 }else if(Roo.isOpera){
5071 if(tag == 'textarea'){
5090 * @class Roo.bootstrap.TextArea
5091 * @extends Roo.bootstrap.Input
5092 * Bootstrap TextArea class
5093 * @cfg {Number} cols Specifies the visible width of a text area
5094 * @cfg {Number} rows Specifies the visible number of lines in a text area
5095 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
5096 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
5097 * @cfg {string} html text
5100 * Create a new TextArea
5101 * @param {Object} config The config object
5104 Roo.bootstrap.TextArea = function(config){
5105 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
5109 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
5119 getAutoCreate : function(){
5121 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
5132 value : this.value || '',
5133 html: this.html || '',
5134 cls : 'form-control',
5135 placeholder : this.placeholder || ''
5139 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
5140 input.maxLength = this.maxLength;
5144 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
5148 input.cols = this.cols;
5151 if (this.readOnly) {
5152 input.readonly = true;
5156 input.name = this.name;
5160 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
5164 ['xs','sm','md','lg'].map(function(size){
5165 if (settings[size]) {
5166 cfg.cls += ' col-' + size + '-' + settings[size];
5170 var inputblock = input;
5172 if (this.before || this.after) {
5175 cls : 'input-group',
5179 inputblock.cn.push({
5181 cls : 'input-group-addon',
5185 inputblock.cn.push(input);
5187 inputblock.cn.push({
5189 cls : 'input-group-addon',
5196 if (align ==='left' && this.fieldLabel.length) {
5197 Roo.log("left and has label");
5203 cls : 'control-label col-sm-' + this.labelWidth,
5204 html : this.fieldLabel
5208 cls : "col-sm-" + (12 - this.labelWidth),
5215 } else if ( this.fieldLabel.length) {
5221 //cls : 'input-group-addon',
5222 html : this.fieldLabel
5232 Roo.log(" no label && no align");
5242 if (this.disabled) {
5243 input.disabled=true;
5250 * return the real textarea element.
5252 inputEl: function ()
5254 return this.el.select('textarea.form-control',true).first();
5262 * trigger field - base class for combo..
5267 * @class Roo.bootstrap.TriggerField
5268 * @extends Roo.bootstrap.Input
5269 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
5270 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
5271 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
5272 * for which you can provide a custom implementation. For example:
5274 var trigger = new Roo.bootstrap.TriggerField();
5275 trigger.onTriggerClick = myTriggerFn;
5276 trigger.applyTo('my-field');
5279 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
5280 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
5281 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
5282 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
5284 * Create a new TriggerField.
5285 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
5286 * to the base TextField)
5288 Roo.bootstrap.TriggerField = function(config){
5289 this.mimicing = false;
5290 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
5293 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
5295 * @cfg {String} triggerClass A CSS class to apply to the trigger
5298 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
5302 /** @cfg {Boolean} grow @hide */
5303 /** @cfg {Number} growMin @hide */
5304 /** @cfg {Number} growMax @hide */
5310 autoSize: Roo.emptyFn,
5317 actionMode : 'wrap',
5321 getAutoCreate : function(){
5323 var parent = this.parent();
5325 var align = this.parentLabelAlign();
5330 cls: 'form-group' //input-group
5337 type : this.inputType,
5338 cls : 'form-control',
5339 autocomplete: 'off',
5340 placeholder : this.placeholder || ''
5344 input.name = this.name;
5347 input.cls += ' input-' + this.size;
5350 if (this.disabled) {
5351 input.disabled=true;
5354 var inputblock = input;
5356 if (this.before || this.after) {
5359 cls : 'input-group',
5363 inputblock.cn.push({
5365 cls : 'input-group-addon',
5369 inputblock.cn.push(input);
5371 inputblock.cn.push({
5373 cls : 'input-group-addon',
5386 cls: 'form-hidden-field'
5394 Roo.log('multiple');
5402 cls: 'form-hidden-field'
5406 cls: 'select2-choices',
5410 cls: 'select2-search-field',
5423 cls: 'select2-container input-group',
5428 cls: 'typeahead typeahead-long dropdown-menu',
5429 style: 'display:none'
5437 cls : 'input-group-addon btn dropdown-toggle',
5445 cls: 'combobox-clear',
5459 combobox.cls += ' select2-container-multi';
5462 if (align ==='left' && this.fieldLabel.length) {
5464 Roo.log("left and has label");
5470 cls : 'control-label col-sm-' + this.labelWidth,
5471 html : this.fieldLabel
5475 cls : "col-sm-" + (12 - this.labelWidth),
5482 } else if ( this.fieldLabel.length) {
5488 //cls : 'input-group-addon',
5489 html : this.fieldLabel
5499 Roo.log(" no label && no align");
5506 ['xs','sm','md','lg'].map(function(size){
5507 if (settings[size]) {
5508 cfg.cls += ' col-' + size + '-' + settings[size];
5519 onResize : function(w, h){
5520 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
5521 // if(typeof w == 'number'){
5522 // var x = w - this.trigger.getWidth();
5523 // this.inputEl().setWidth(this.adjustWidth('input', x));
5524 // this.trigger.setStyle('left', x+'px');
5529 adjustSize : Roo.BoxComponent.prototype.adjustSize,
5532 getResizeEl : function(){
5533 return this.inputEl();
5537 getPositionEl : function(){
5538 return this.inputEl();
5542 alignErrorIcon : function(){
5543 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
5547 initEvents : function(){
5549 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
5550 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
5552 this.trigger = this.el.select('span.dropdown-toggle',true).first();
5553 if(this.hideTrigger){
5554 this.trigger.setDisplayed(false);
5556 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
5560 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
5563 //this.trigger.addClassOnOver('x-form-trigger-over');
5564 //this.trigger.addClassOnClick('x-form-trigger-click');
5567 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
5572 initTrigger : function(){
5577 onDestroy : function(){
5579 this.trigger.removeAllListeners();
5580 // this.trigger.remove();
5583 // this.wrap.remove();
5585 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
5589 onFocus : function(){
5590 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
5593 this.wrap.addClass('x-trigger-wrap-focus');
5594 this.mimicing = true;
5595 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
5596 if(this.monitorTab){
5597 this.el.on("keydown", this.checkTab, this);
5604 checkTab : function(e){
5605 if(e.getKey() == e.TAB){
5611 onBlur : function(){
5616 mimicBlur : function(e, t){
5618 if(!this.wrap.contains(t) && this.validateBlur()){
5625 triggerBlur : function(){
5626 this.mimicing = false;
5627 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
5628 if(this.monitorTab){
5629 this.el.un("keydown", this.checkTab, this);
5631 //this.wrap.removeClass('x-trigger-wrap-focus');
5632 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
5636 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
5637 validateBlur : function(e, t){
5642 onDisable : function(){
5643 Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
5645 // this.wrap.addClass('x-item-disabled');
5650 onEnable : function(){
5651 Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
5653 // this.el.removeClass('x-item-disabled');
5658 onShow : function(){
5659 var ae = this.getActionEl();
5662 ae.dom.style.display = '';
5663 ae.dom.style.visibility = 'visible';
5669 onHide : function(){
5670 var ae = this.getActionEl();
5671 ae.dom.style.display = 'none';
5675 * The function that should handle the trigger's click event. This method does nothing by default until overridden
5676 * by an implementing function.
5678 * @param {EventObject} e
5680 onTriggerClick : Roo.emptyFn
5684 * Ext JS Library 1.1.1
5685 * Copyright(c) 2006-2007, Ext JS, LLC.
5687 * Originally Released Under LGPL - original licence link has changed is not relivant.
5690 * <script type="text/javascript">
5695 * @class Roo.data.SortTypes
5697 * Defines the default sorting (casting?) comparison functions used when sorting data.
5699 Roo.data.SortTypes = {
5701 * Default sort that does nothing
5702 * @param {Mixed} s The value being converted
5703 * @return {Mixed} The comparison value
5710 * The regular expression used to strip tags
5714 stripTagsRE : /<\/?[^>]+>/gi,
5717 * Strips all HTML tags to sort on text only
5718 * @param {Mixed} s The value being converted
5719 * @return {String} The comparison value
5721 asText : function(s){
5722 return String(s).replace(this.stripTagsRE, "");
5726 * Strips all HTML tags to sort on text only - Case insensitive
5727 * @param {Mixed} s The value being converted
5728 * @return {String} The comparison value
5730 asUCText : function(s){
5731 return String(s).toUpperCase().replace(this.stripTagsRE, "");
5735 * Case insensitive string
5736 * @param {Mixed} s The value being converted
5737 * @return {String} The comparison value
5739 asUCString : function(s) {
5740 return String(s).toUpperCase();
5745 * @param {Mixed} s The value being converted
5746 * @return {Number} The comparison value
5748 asDate : function(s) {
5752 if(s instanceof Date){
5755 return Date.parse(String(s));
5760 * @param {Mixed} s The value being converted
5761 * @return {Float} The comparison value
5763 asFloat : function(s) {
5764 var val = parseFloat(String(s).replace(/,/g, ""));
5765 if(isNaN(val)) val = 0;
5771 * @param {Mixed} s The value being converted
5772 * @return {Number} The comparison value
5774 asInt : function(s) {
5775 var val = parseInt(String(s).replace(/,/g, ""));
5776 if(isNaN(val)) val = 0;
5781 * Ext JS Library 1.1.1
5782 * Copyright(c) 2006-2007, Ext JS, LLC.
5784 * Originally Released Under LGPL - original licence link has changed is not relivant.
5787 * <script type="text/javascript">
5791 * @class Roo.data.Record
5792 * Instances of this class encapsulate both record <em>definition</em> information, and record
5793 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
5794 * to access Records cached in an {@link Roo.data.Store} object.<br>
5796 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
5797 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
5800 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
5802 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
5803 * {@link #create}. The parameters are the same.
5804 * @param {Array} data An associative Array of data values keyed by the field name.
5805 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
5806 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
5807 * not specified an integer id is generated.
5809 Roo.data.Record = function(data, id){
5810 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
5815 * Generate a constructor for a specific record layout.
5816 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
5817 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
5818 * Each field definition object may contain the following properties: <ul>
5819 * <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,
5820 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
5821 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
5822 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
5823 * is being used, then this is a string containing the javascript expression to reference the data relative to
5824 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
5825 * to the data item relative to the record element. If the mapping expression is the same as the field name,
5826 * this may be omitted.</p></li>
5827 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
5828 * <ul><li>auto (Default, implies no conversion)</li>
5833 * <li>date</li></ul></p></li>
5834 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
5835 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
5836 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
5837 * by the Reader into an object that will be stored in the Record. It is passed the
5838 * following parameters:<ul>
5839 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
5841 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
5843 * <br>usage:<br><pre><code>
5844 var TopicRecord = Roo.data.Record.create(
5845 {name: 'title', mapping: 'topic_title'},
5846 {name: 'author', mapping: 'username'},
5847 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
5848 {name: 'lastPost', mapping: 'post_time', type: 'date'},
5849 {name: 'lastPoster', mapping: 'user2'},
5850 {name: 'excerpt', mapping: 'post_text'}
5853 var myNewRecord = new TopicRecord({
5854 title: 'Do my job please',
5857 lastPost: new Date(),
5858 lastPoster: 'Animal',
5859 excerpt: 'No way dude!'
5861 myStore.add(myNewRecord);
5866 Roo.data.Record.create = function(o){
5868 f.superclass.constructor.apply(this, arguments);
5870 Roo.extend(f, Roo.data.Record);
5871 var p = f.prototype;
5872 p.fields = new Roo.util.MixedCollection(false, function(field){
5875 for(var i = 0, len = o.length; i < len; i++){
5876 p.fields.add(new Roo.data.Field(o[i]));
5878 f.getField = function(name){
5879 return p.fields.get(name);
5884 Roo.data.Record.AUTO_ID = 1000;
5885 Roo.data.Record.EDIT = 'edit';
5886 Roo.data.Record.REJECT = 'reject';
5887 Roo.data.Record.COMMIT = 'commit';
5889 Roo.data.Record.prototype = {
5891 * Readonly flag - true if this record has been modified.
5900 join : function(store){
5905 * Set the named field to the specified value.
5906 * @param {String} name The name of the field to set.
5907 * @param {Object} value The value to set the field to.
5909 set : function(name, value){
5910 if(this.data[name] == value){
5917 if(typeof this.modified[name] == 'undefined'){
5918 this.modified[name] = this.data[name];
5920 this.data[name] = value;
5921 if(!this.editing && this.store){
5922 this.store.afterEdit(this);
5927 * Get the value of the named field.
5928 * @param {String} name The name of the field to get the value of.
5929 * @return {Object} The value of the field.
5931 get : function(name){
5932 return this.data[name];
5936 beginEdit : function(){
5937 this.editing = true;
5942 cancelEdit : function(){
5943 this.editing = false;
5944 delete this.modified;
5948 endEdit : function(){
5949 this.editing = false;
5950 if(this.dirty && this.store){
5951 this.store.afterEdit(this);
5956 * Usually called by the {@link Roo.data.Store} which owns the Record.
5957 * Rejects all changes made to the Record since either creation, or the last commit operation.
5958 * Modified fields are reverted to their original values.
5960 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
5961 * of reject operations.
5963 reject : function(){
5964 var m = this.modified;
5966 if(typeof m[n] != "function"){
5967 this.data[n] = m[n];
5971 delete this.modified;
5972 this.editing = false;
5974 this.store.afterReject(this);
5979 * Usually called by the {@link Roo.data.Store} which owns the Record.
5980 * Commits all changes made to the Record since either creation, or the last commit operation.
5982 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
5983 * of commit operations.
5985 commit : function(){
5987 delete this.modified;
5988 this.editing = false;
5990 this.store.afterCommit(this);
5995 hasError : function(){
5996 return this.error != null;
6000 clearError : function(){
6005 * Creates a copy of this record.
6006 * @param {String} id (optional) A new record id if you don't want to use this record's id
6009 copy : function(newId) {
6010 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
6014 * Ext JS Library 1.1.1
6015 * Copyright(c) 2006-2007, Ext JS, LLC.
6017 * Originally Released Under LGPL - original licence link has changed is not relivant.
6020 * <script type="text/javascript">
6026 * @class Roo.data.Store
6027 * @extends Roo.util.Observable
6028 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
6029 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
6031 * 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
6032 * has no knowledge of the format of the data returned by the Proxy.<br>
6034 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
6035 * instances from the data object. These records are cached and made available through accessor functions.
6037 * Creates a new Store.
6038 * @param {Object} config A config object containing the objects needed for the Store to access data,
6039 * and read the data into Records.
6041 Roo.data.Store = function(config){
6042 this.data = new Roo.util.MixedCollection(false);
6043 this.data.getKey = function(o){
6046 this.baseParams = {};
6053 "multisort" : "_multisort"
6056 if(config && config.data){
6057 this.inlineData = config.data;
6061 Roo.apply(this, config);
6063 if(this.reader){ // reader passed
6064 this.reader = Roo.factory(this.reader, Roo.data);
6065 this.reader.xmodule = this.xmodule || false;
6066 if(!this.recordType){
6067 this.recordType = this.reader.recordType;
6069 if(this.reader.onMetaChange){
6070 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
6074 if(this.recordType){
6075 this.fields = this.recordType.prototype.fields;
6081 * @event datachanged
6082 * Fires when the data cache has changed, and a widget which is using this Store
6083 * as a Record cache should refresh its view.
6084 * @param {Store} this
6089 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
6090 * @param {Store} this
6091 * @param {Object} meta The JSON metadata
6096 * Fires when Records have been added to the Store
6097 * @param {Store} this
6098 * @param {Roo.data.Record[]} records The array of Records added
6099 * @param {Number} index The index at which the record(s) were added
6104 * Fires when a Record has been removed from the Store
6105 * @param {Store} this
6106 * @param {Roo.data.Record} record The Record that was removed
6107 * @param {Number} index The index at which the record was removed
6112 * Fires when a Record has been updated
6113 * @param {Store} this
6114 * @param {Roo.data.Record} record The Record that was updated
6115 * @param {String} operation The update operation being performed. Value may be one of:
6117 Roo.data.Record.EDIT
6118 Roo.data.Record.REJECT
6119 Roo.data.Record.COMMIT
6125 * Fires when the data cache has been cleared.
6126 * @param {Store} this
6131 * Fires before a request is made for a new data object. If the beforeload handler returns false
6132 * the load action will be canceled.
6133 * @param {Store} this
6134 * @param {Object} options The loading options that were specified (see {@link #load} for details)
6138 * @event beforeloadadd
6139 * Fires after a new set of Records has been loaded.
6140 * @param {Store} this
6141 * @param {Roo.data.Record[]} records The Records that were loaded
6142 * @param {Object} options The loading options that were specified (see {@link #load} for details)
6144 beforeloadadd : true,
6147 * Fires after a new set of Records has been loaded, before they are added to the store.
6148 * @param {Store} this
6149 * @param {Roo.data.Record[]} records The Records that were loaded
6150 * @param {Object} options The loading options that were specified (see {@link #load} for details)
6151 * @params {Object} return from reader
6155 * @event loadexception
6156 * Fires if an exception occurs in the Proxy during loading.
6157 * Called with the signature of the Proxy's "loadexception" event.
6158 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
6161 * @param {Object} return from JsonData.reader() - success, totalRecords, records
6162 * @param {Object} load options
6163 * @param {Object} jsonData from your request (normally this contains the Exception)
6165 loadexception : true
6169 this.proxy = Roo.factory(this.proxy, Roo.data);
6170 this.proxy.xmodule = this.xmodule || false;
6171 this.relayEvents(this.proxy, ["loadexception"]);
6173 this.sortToggle = {};
6174 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
6176 Roo.data.Store.superclass.constructor.call(this);
6178 if(this.inlineData){
6179 this.loadData(this.inlineData);
6180 delete this.inlineData;
6184 Roo.extend(Roo.data.Store, Roo.util.Observable, {
6186 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
6187 * without a remote query - used by combo/forms at present.
6191 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
6194 * @cfg {Array} data Inline data to be loaded when the store is initialized.
6197 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
6198 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
6201 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
6202 * on any HTTP request
6205 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
6208 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
6212 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
6213 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
6218 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
6219 * loaded or when a record is removed. (defaults to false).
6221 pruneModifiedRecords : false,
6227 * Add Records to the Store and fires the add event.
6228 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
6230 add : function(records){
6231 records = [].concat(records);
6232 for(var i = 0, len = records.length; i < len; i++){
6233 records[i].join(this);
6235 var index = this.data.length;
6236 this.data.addAll(records);
6237 this.fireEvent("add", this, records, index);
6241 * Remove a Record from the Store and fires the remove event.
6242 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
6244 remove : function(record){
6245 var index = this.data.indexOf(record);
6246 this.data.removeAt(index);
6247 if(this.pruneModifiedRecords){
6248 this.modified.remove(record);
6250 this.fireEvent("remove", this, record, index);
6254 * Remove all Records from the Store and fires the clear event.
6256 removeAll : function(){
6258 if(this.pruneModifiedRecords){
6261 this.fireEvent("clear", this);
6265 * Inserts Records to the Store at the given index and fires the add event.
6266 * @param {Number} index The start index at which to insert the passed Records.
6267 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
6269 insert : function(index, records){
6270 records = [].concat(records);
6271 for(var i = 0, len = records.length; i < len; i++){
6272 this.data.insert(index, records[i]);
6273 records[i].join(this);
6275 this.fireEvent("add", this, records, index);
6279 * Get the index within the cache of the passed Record.
6280 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
6281 * @return {Number} The index of the passed Record. Returns -1 if not found.
6283 indexOf : function(record){
6284 return this.data.indexOf(record);
6288 * Get the index within the cache of the Record with the passed id.
6289 * @param {String} id The id of the Record to find.
6290 * @return {Number} The index of the Record. Returns -1 if not found.
6292 indexOfId : function(id){
6293 return this.data.indexOfKey(id);
6297 * Get the Record with the specified id.
6298 * @param {String} id The id of the Record to find.
6299 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
6301 getById : function(id){
6302 return this.data.key(id);
6306 * Get the Record at the specified index.
6307 * @param {Number} index The index of the Record to find.
6308 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
6310 getAt : function(index){
6311 return this.data.itemAt(index);
6315 * Returns a range of Records between specified indices.
6316 * @param {Number} startIndex (optional) The starting index (defaults to 0)
6317 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
6318 * @return {Roo.data.Record[]} An array of Records
6320 getRange : function(start, end){
6321 return this.data.getRange(start, end);
6325 storeOptions : function(o){
6326 o = Roo.apply({}, o);
6329 this.lastOptions = o;
6333 * Loads the Record cache from the configured Proxy using the configured Reader.
6335 * If using remote paging, then the first load call must specify the <em>start</em>
6336 * and <em>limit</em> properties in the options.params property to establish the initial
6337 * position within the dataset, and the number of Records to cache on each read from the Proxy.
6339 * <strong>It is important to note that for remote data sources, loading is asynchronous,
6340 * and this call will return before the new data has been loaded. Perform any post-processing
6341 * in a callback function, or in a "load" event handler.</strong>
6343 * @param {Object} options An object containing properties which control loading options:<ul>
6344 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
6345 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
6346 * passed the following arguments:<ul>
6347 * <li>r : Roo.data.Record[]</li>
6348 * <li>options: Options object from the load call</li>
6349 * <li>success: Boolean success indicator</li></ul></li>
6350 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
6351 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
6354 load : function(options){
6355 options = options || {};
6356 if(this.fireEvent("beforeload", this, options) !== false){
6357 this.storeOptions(options);
6358 var p = Roo.apply(options.params || {}, this.baseParams);
6359 // if meta was not loaded from remote source.. try requesting it.
6360 if (!this.reader.metaFromRemote) {
6363 if(this.sortInfo && this.remoteSort){
6364 var pn = this.paramNames;
6365 p[pn["sort"]] = this.sortInfo.field;
6366 p[pn["dir"]] = this.sortInfo.direction;
6368 if (this.multiSort) {
6369 var pn = this.paramNames;
6370 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
6373 this.proxy.load(p, this.reader, this.loadRecords, this, options);
6378 * Reloads the Record cache from the configured Proxy using the configured Reader and
6379 * the options from the last load operation performed.
6380 * @param {Object} options (optional) An object containing properties which may override the options
6381 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
6382 * the most recently used options are reused).
6384 reload : function(options){
6385 this.load(Roo.applyIf(options||{}, this.lastOptions));
6389 // Called as a callback by the Reader during a load operation.
6390 loadRecords : function(o, options, success){
6391 if(!o || success === false){
6392 if(success !== false){
6393 this.fireEvent("load", this, [], options, o);
6395 if(options.callback){
6396 options.callback.call(options.scope || this, [], options, false);
6400 // if data returned failure - throw an exception.
6401 if (o.success === false) {
6402 // show a message if no listener is registered.
6403 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
6404 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
6406 // loadmask wil be hooked into this..
6407 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
6410 var r = o.records, t = o.totalRecords || r.length;
6412 this.fireEvent("beforeloadadd", this, r, options, o);
6414 if(!options || options.add !== true){
6415 if(this.pruneModifiedRecords){
6418 for(var i = 0, len = r.length; i < len; i++){
6422 this.data = this.snapshot;
6423 delete this.snapshot;
6426 this.data.addAll(r);
6427 this.totalLength = t;
6429 this.fireEvent("datachanged", this);
6431 this.totalLength = Math.max(t, this.data.length+r.length);
6434 this.fireEvent("load", this, r, options, o);
6435 if(options.callback){
6436 options.callback.call(options.scope || this, r, options, true);
6442 * Loads data from a passed data block. A Reader which understands the format of the data
6443 * must have been configured in the constructor.
6444 * @param {Object} data The data block from which to read the Records. The format of the data expected
6445 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
6446 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
6448 loadData : function(o, append){
6449 var r = this.reader.readRecords(o);
6450 this.loadRecords(r, {add: append}, true);
6454 * Gets the number of cached records.
6456 * <em>If using paging, this may not be the total size of the dataset. If the data object
6457 * used by the Reader contains the dataset size, then the getTotalCount() function returns
6458 * the data set size</em>
6460 getCount : function(){
6461 return this.data.length || 0;
6465 * Gets the total number of records in the dataset as returned by the server.
6467 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
6468 * the dataset size</em>
6470 getTotalCount : function(){
6471 return this.totalLength || 0;
6475 * Returns the sort state of the Store as an object with two properties:
6477 field {String} The name of the field by which the Records are sorted
6478 direction {String} The sort order, "ASC" or "DESC"
6481 getSortState : function(){
6482 return this.sortInfo;
6486 applySort : function(){
6487 if(this.sortInfo && !this.remoteSort){
6488 var s = this.sortInfo, f = s.field;
6489 var st = this.fields.get(f).sortType;
6490 var fn = function(r1, r2){
6491 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
6492 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
6494 this.data.sort(s.direction, fn);
6495 if(this.snapshot && this.snapshot != this.data){
6496 this.snapshot.sort(s.direction, fn);
6502 * Sets the default sort column and order to be used by the next load operation.
6503 * @param {String} fieldName The name of the field to sort by.
6504 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
6506 setDefaultSort : function(field, dir){
6507 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
6512 * If remote sorting is used, the sort is performed on the server, and the cache is
6513 * reloaded. If local sorting is used, the cache is sorted internally.
6514 * @param {String} fieldName The name of the field to sort by.
6515 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
6517 sort : function(fieldName, dir){
6518 var f = this.fields.get(fieldName);
6520 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
6522 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
6523 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
6528 this.sortToggle[f.name] = dir;
6529 this.sortInfo = {field: f.name, direction: dir};
6530 if(!this.remoteSort){
6532 this.fireEvent("datachanged", this);
6534 this.load(this.lastOptions);
6539 * Calls the specified function for each of the Records in the cache.
6540 * @param {Function} fn The function to call. The Record is passed as the first parameter.
6541 * Returning <em>false</em> aborts and exits the iteration.
6542 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
6544 each : function(fn, scope){
6545 this.data.each(fn, scope);
6549 * Gets all records modified since the last commit. Modified records are persisted across load operations
6550 * (e.g., during paging).
6551 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
6553 getModifiedRecords : function(){
6554 return this.modified;
6558 createFilterFn : function(property, value, anyMatch){
6559 if(!value.exec){ // not a regex
6560 value = String(value);
6561 if(value.length == 0){
6564 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
6567 return value.test(r.data[property]);
6572 * Sums the value of <i>property</i> for each record between start and end and returns the result.
6573 * @param {String} property A field on your records
6574 * @param {Number} start The record index to start at (defaults to 0)
6575 * @param {Number} end The last record index to include (defaults to length - 1)
6576 * @return {Number} The sum
6578 sum : function(property, start, end){
6579 var rs = this.data.items, v = 0;
6581 end = (end || end === 0) ? end : rs.length-1;
6583 for(var i = start; i <= end; i++){
6584 v += (rs[i].data[property] || 0);
6590 * Filter the records by a specified property.
6591 * @param {String} field A field on your records
6592 * @param {String/RegExp} value Either a string that the field
6593 * should start with or a RegExp to test against the field
6594 * @param {Boolean} anyMatch True to match any part not just the beginning
6596 filter : function(property, value, anyMatch){
6597 var fn = this.createFilterFn(property, value, anyMatch);
6598 return fn ? this.filterBy(fn) : this.clearFilter();
6602 * Filter by a function. The specified function will be called with each
6603 * record in this data source. If the function returns true the record is included,
6604 * otherwise it is filtered.
6605 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
6606 * @param {Object} scope (optional) The scope of the function (defaults to this)
6608 filterBy : function(fn, scope){
6609 this.snapshot = this.snapshot || this.data;
6610 this.data = this.queryBy(fn, scope||this);
6611 this.fireEvent("datachanged", this);
6615 * Query the records by a specified property.
6616 * @param {String} field A field on your records
6617 * @param {String/RegExp} value Either a string that the field
6618 * should start with or a RegExp to test against the field
6619 * @param {Boolean} anyMatch True to match any part not just the beginning
6620 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
6622 query : function(property, value, anyMatch){
6623 var fn = this.createFilterFn(property, value, anyMatch);
6624 return fn ? this.queryBy(fn) : this.data.clone();
6628 * Query by a function. The specified function will be called with each
6629 * record in this data source. If the function returns true the record is included
6631 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
6632 * @param {Object} scope (optional) The scope of the function (defaults to this)
6633 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
6635 queryBy : function(fn, scope){
6636 var data = this.snapshot || this.data;
6637 return data.filterBy(fn, scope||this);
6641 * Collects unique values for a particular dataIndex from this store.
6642 * @param {String} dataIndex The property to collect
6643 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
6644 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
6645 * @return {Array} An array of the unique values
6647 collect : function(dataIndex, allowNull, bypassFilter){
6648 var d = (bypassFilter === true && this.snapshot) ?
6649 this.snapshot.items : this.data.items;
6650 var v, sv, r = [], l = {};
6651 for(var i = 0, len = d.length; i < len; i++){
6652 v = d[i].data[dataIndex];
6654 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
6663 * Revert to a view of the Record cache with no filtering applied.
6664 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
6666 clearFilter : function(suppressEvent){
6667 if(this.snapshot && this.snapshot != this.data){
6668 this.data = this.snapshot;
6669 delete this.snapshot;
6670 if(suppressEvent !== true){
6671 this.fireEvent("datachanged", this);
6677 afterEdit : function(record){
6678 if(this.modified.indexOf(record) == -1){
6679 this.modified.push(record);
6681 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
6685 afterReject : function(record){
6686 this.modified.remove(record);
6687 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
6691 afterCommit : function(record){
6692 this.modified.remove(record);
6693 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
6697 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
6698 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
6700 commitChanges : function(){
6701 var m = this.modified.slice(0);
6703 for(var i = 0, len = m.length; i < len; i++){
6709 * Cancel outstanding changes on all changed records.
6711 rejectChanges : function(){
6712 var m = this.modified.slice(0);
6714 for(var i = 0, len = m.length; i < len; i++){
6719 onMetaChange : function(meta, rtype, o){
6720 this.recordType = rtype;
6721 this.fields = rtype.prototype.fields;
6722 delete this.snapshot;
6723 this.sortInfo = meta.sortInfo || this.sortInfo;
6725 this.fireEvent('metachange', this, this.reader.meta);
6729 * Ext JS Library 1.1.1
6730 * Copyright(c) 2006-2007, Ext JS, LLC.
6732 * Originally Released Under LGPL - original licence link has changed is not relivant.
6735 * <script type="text/javascript">
6739 * @class Roo.data.SimpleStore
6740 * @extends Roo.data.Store
6741 * Small helper class to make creating Stores from Array data easier.
6742 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
6743 * @cfg {Array} fields An array of field definition objects, or field name strings.
6744 * @cfg {Array} data The multi-dimensional array of data
6746 * @param {Object} config
6748 Roo.data.SimpleStore = function(config){
6749 Roo.data.SimpleStore.superclass.constructor.call(this, {
6751 reader: new Roo.data.ArrayReader({
6754 Roo.data.Record.create(config.fields)
6756 proxy : new Roo.data.MemoryProxy(config.data)
6760 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
6762 * Ext JS Library 1.1.1
6763 * Copyright(c) 2006-2007, Ext JS, LLC.
6765 * Originally Released Under LGPL - original licence link has changed is not relivant.
6768 * <script type="text/javascript">
6773 * @extends Roo.data.Store
6774 * @class Roo.data.JsonStore
6775 * Small helper class to make creating Stores for JSON data easier. <br/>
6777 var store = new Roo.data.JsonStore({
6778 url: 'get-images.php',
6780 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
6783 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
6784 * JsonReader and HttpProxy (unless inline data is provided).</b>
6785 * @cfg {Array} fields An array of field definition objects, or field name strings.
6787 * @param {Object} config
6789 Roo.data.JsonStore = function(c){
6790 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
6791 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
6792 reader: new Roo.data.JsonReader(c, c.fields)
6795 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
6797 * Ext JS Library 1.1.1
6798 * Copyright(c) 2006-2007, Ext JS, LLC.
6800 * Originally Released Under LGPL - original licence link has changed is not relivant.
6803 * <script type="text/javascript">
6807 Roo.data.Field = function(config){
6808 if(typeof config == "string"){
6809 config = {name: config};
6811 Roo.apply(this, config);
6817 var st = Roo.data.SortTypes;
6818 // named sortTypes are supported, here we look them up
6819 if(typeof this.sortType == "string"){
6820 this.sortType = st[this.sortType];
6823 // set default sortType for strings and dates
6827 this.sortType = st.asUCString;
6830 this.sortType = st.asDate;
6833 this.sortType = st.none;
6838 var stripRe = /[\$,%]/g;
6840 // prebuilt conversion function for this field, instead of
6841 // switching every time we're reading a value
6843 var cv, dateFormat = this.dateFormat;
6848 cv = function(v){ return v; };
6851 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
6855 return v !== undefined && v !== null && v !== '' ?
6856 parseInt(String(v).replace(stripRe, ""), 10) : '';
6861 return v !== undefined && v !== null && v !== '' ?
6862 parseFloat(String(v).replace(stripRe, ""), 10) : '';
6867 cv = function(v){ return v === true || v === "true" || v == 1; };
6874 if(v instanceof Date){
6878 if(dateFormat == "timestamp"){
6879 return new Date(v*1000);
6881 return Date.parseDate(v, dateFormat);
6883 var parsed = Date.parse(v);
6884 return parsed ? new Date(parsed) : null;
6893 Roo.data.Field.prototype = {
6901 * Ext JS Library 1.1.1
6902 * Copyright(c) 2006-2007, Ext JS, LLC.
6904 * Originally Released Under LGPL - original licence link has changed is not relivant.
6907 * <script type="text/javascript">
6910 // Base class for reading structured data from a data source. This class is intended to be
6911 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
6914 * @class Roo.data.DataReader
6915 * Base class for reading structured data from a data source. This class is intended to be
6916 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
6919 Roo.data.DataReader = function(meta, recordType){
6923 this.recordType = recordType instanceof Array ?
6924 Roo.data.Record.create(recordType) : recordType;
6927 Roo.data.DataReader.prototype = {
6929 * Create an empty record
6930 * @param {Object} data (optional) - overlay some values
6931 * @return {Roo.data.Record} record created.
6933 newRow : function(d) {
6935 this.recordType.prototype.fields.each(function(c) {
6937 case 'int' : da[c.name] = 0; break;
6938 case 'date' : da[c.name] = new Date(); break;
6939 case 'float' : da[c.name] = 0.0; break;
6940 case 'boolean' : da[c.name] = false; break;
6941 default : da[c.name] = ""; break;
6945 return new this.recordType(Roo.apply(da, d));
6950 * Ext JS Library 1.1.1
6951 * Copyright(c) 2006-2007, Ext JS, LLC.
6953 * Originally Released Under LGPL - original licence link has changed is not relivant.
6956 * <script type="text/javascript">
6960 * @class Roo.data.DataProxy
6961 * @extends Roo.data.Observable
6962 * This class is an abstract base class for implementations which provide retrieval of
6963 * unformatted data objects.<br>
6965 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
6966 * (of the appropriate type which knows how to parse the data object) to provide a block of
6967 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
6969 * Custom implementations must implement the load method as described in
6970 * {@link Roo.data.HttpProxy#load}.
6972 Roo.data.DataProxy = function(){
6976 * Fires before a network request is made to retrieve a data object.
6977 * @param {Object} This DataProxy object.
6978 * @param {Object} params The params parameter to the load function.
6983 * Fires before the load method's callback is called.
6984 * @param {Object} This DataProxy object.
6985 * @param {Object} o The data object.
6986 * @param {Object} arg The callback argument object passed to the load function.
6990 * @event loadexception
6991 * Fires if an Exception occurs during data retrieval.
6992 * @param {Object} This DataProxy object.
6993 * @param {Object} o The data object.
6994 * @param {Object} arg The callback argument object passed to the load function.
6995 * @param {Object} e The Exception.
6997 loadexception : true
6999 Roo.data.DataProxy.superclass.constructor.call(this);
7002 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
7005 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
7009 * Ext JS Library 1.1.1
7010 * Copyright(c) 2006-2007, Ext JS, LLC.
7012 * Originally Released Under LGPL - original licence link has changed is not relivant.
7015 * <script type="text/javascript">
7018 * @class Roo.data.MemoryProxy
7019 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
7020 * to the Reader when its load method is called.
7022 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
7024 Roo.data.MemoryProxy = function(data){
7028 Roo.data.MemoryProxy.superclass.constructor.call(this);
7032 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
7034 * Load data from the requested source (in this case an in-memory
7035 * data object passed to the constructor), read the data object into
7036 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
7037 * process that block using the passed callback.
7038 * @param {Object} params This parameter is not used by the MemoryProxy class.
7039 * @param {Roo.data.DataReader} reader The Reader object which converts the data
7040 * object into a block of Roo.data.Records.
7041 * @param {Function} callback The function into which to pass the block of Roo.data.records.
7042 * The function must be passed <ul>
7043 * <li>The Record block object</li>
7044 * <li>The "arg" argument from the load function</li>
7045 * <li>A boolean success indicator</li>
7047 * @param {Object} scope The scope in which to call the callback
7048 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
7050 load : function(params, reader, callback, scope, arg){
7051 params = params || {};
7054 result = reader.readRecords(this.data);
7056 this.fireEvent("loadexception", this, arg, null, e);
7057 callback.call(scope, null, arg, false);
7060 callback.call(scope, result, arg, true);
7064 update : function(params, records){
7069 * Ext JS Library 1.1.1
7070 * Copyright(c) 2006-2007, Ext JS, LLC.
7072 * Originally Released Under LGPL - original licence link has changed is not relivant.
7075 * <script type="text/javascript">
7078 * @class Roo.data.HttpProxy
7079 * @extends Roo.data.DataProxy
7080 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
7081 * configured to reference a certain URL.<br><br>
7083 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
7084 * from which the running page was served.<br><br>
7086 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
7088 * Be aware that to enable the browser to parse an XML document, the server must set
7089 * the Content-Type header in the HTTP response to "text/xml".
7091 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
7092 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
7093 * will be used to make the request.
7095 Roo.data.HttpProxy = function(conn){
7096 Roo.data.HttpProxy.superclass.constructor.call(this);
7097 // is conn a conn config or a real conn?
7099 this.useAjax = !conn || !conn.events;
7103 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
7104 // thse are take from connection...
7107 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
7110 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
7111 * extra parameters to each request made by this object. (defaults to undefined)
7114 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
7115 * to each request made by this object. (defaults to undefined)
7118 * @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)
7121 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
7124 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
7130 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
7134 * Return the {@link Roo.data.Connection} object being used by this Proxy.
7135 * @return {Connection} The Connection object. This object may be used to subscribe to events on
7136 * a finer-grained basis than the DataProxy events.
7138 getConnection : function(){
7139 return this.useAjax ? Roo.Ajax : this.conn;
7143 * Load data from the configured {@link Roo.data.Connection}, read the data object into
7144 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
7145 * process that block using the passed callback.
7146 * @param {Object} params An object containing properties which are to be used as HTTP parameters
7147 * for the request to the remote server.
7148 * @param {Roo.data.DataReader} reader The Reader object which converts the data
7149 * object into a block of Roo.data.Records.
7150 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
7151 * The function must be passed <ul>
7152 * <li>The Record block object</li>
7153 * <li>The "arg" argument from the load function</li>
7154 * <li>A boolean success indicator</li>
7156 * @param {Object} scope The scope in which to call the callback
7157 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
7159 load : function(params, reader, callback, scope, arg){
7160 if(this.fireEvent("beforeload", this, params) !== false){
7162 params : params || {},
7164 callback : callback,
7169 callback : this.loadResponse,
7173 Roo.applyIf(o, this.conn);
7174 if(this.activeRequest){
7175 Roo.Ajax.abort(this.activeRequest);
7177 this.activeRequest = Roo.Ajax.request(o);
7179 this.conn.request(o);
7182 callback.call(scope||this, null, arg, false);
7187 loadResponse : function(o, success, response){
7188 delete this.activeRequest;
7190 this.fireEvent("loadexception", this, o, response);
7191 o.request.callback.call(o.request.scope, null, o.request.arg, false);
7196 result = o.reader.read(response);
7198 this.fireEvent("loadexception", this, o, response, e);
7199 o.request.callback.call(o.request.scope, null, o.request.arg, false);
7203 this.fireEvent("load", this, o, o.request.arg);
7204 o.request.callback.call(o.request.scope, result, o.request.arg, true);
7208 update : function(dataSet){
7213 updateResponse : function(dataSet){
7218 * Ext JS Library 1.1.1
7219 * Copyright(c) 2006-2007, Ext JS, LLC.
7221 * Originally Released Under LGPL - original licence link has changed is not relivant.
7224 * <script type="text/javascript">
7228 * @class Roo.data.ScriptTagProxy
7229 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
7230 * other than the originating domain of the running page.<br><br>
7232 * <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
7233 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
7235 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
7236 * source code that is used as the source inside a <script> tag.<br><br>
7238 * In order for the browser to process the returned data, the server must wrap the data object
7239 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
7240 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
7241 * depending on whether the callback name was passed:
7244 boolean scriptTag = false;
7245 String cb = request.getParameter("callback");
7248 response.setContentType("text/javascript");
7250 response.setContentType("application/x-json");
7252 Writer out = response.getWriter();
7254 out.write(cb + "(");
7256 out.print(dataBlock.toJsonString());
7263 * @param {Object} config A configuration object.
7265 Roo.data.ScriptTagProxy = function(config){
7266 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
7267 Roo.apply(this, config);
7268 this.head = document.getElementsByTagName("head")[0];
7271 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
7273 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
7275 * @cfg {String} url The URL from which to request the data object.
7278 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
7282 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
7283 * the server the name of the callback function set up by the load call to process the returned data object.
7284 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
7285 * javascript output which calls this named function passing the data object as its only parameter.
7287 callbackParam : "callback",
7289 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
7290 * name to the request.
7295 * Load data from the configured URL, read the data object into
7296 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
7297 * process that block using the passed callback.
7298 * @param {Object} params An object containing properties which are to be used as HTTP parameters
7299 * for the request to the remote server.
7300 * @param {Roo.data.DataReader} reader The Reader object which converts the data
7301 * object into a block of Roo.data.Records.
7302 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
7303 * The function must be passed <ul>
7304 * <li>The Record block object</li>
7305 * <li>The "arg" argument from the load function</li>
7306 * <li>A boolean success indicator</li>
7308 * @param {Object} scope The scope in which to call the callback
7309 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
7311 load : function(params, reader, callback, scope, arg){
7312 if(this.fireEvent("beforeload", this, params) !== false){
7314 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
7317 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
7319 url += "&_dc=" + (new Date().getTime());
7321 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
7324 cb : "stcCallback"+transId,
7325 scriptId : "stcScript"+transId,
7329 callback : callback,
7335 window[trans.cb] = function(o){
7336 conn.handleResponse(o, trans);
7339 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
7341 if(this.autoAbort !== false){
7345 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
7347 var script = document.createElement("script");
7348 script.setAttribute("src", url);
7349 script.setAttribute("type", "text/javascript");
7350 script.setAttribute("id", trans.scriptId);
7351 this.head.appendChild(script);
7355 callback.call(scope||this, null, arg, false);
7360 isLoading : function(){
7361 return this.trans ? true : false;
7365 * Abort the current server request.
7368 if(this.isLoading()){
7369 this.destroyTrans(this.trans);
7374 destroyTrans : function(trans, isLoaded){
7375 this.head.removeChild(document.getElementById(trans.scriptId));
7376 clearTimeout(trans.timeoutId);
7378 window[trans.cb] = undefined;
7380 delete window[trans.cb];
7383 // if hasn't been loaded, wait for load to remove it to prevent script error
7384 window[trans.cb] = function(){
7385 window[trans.cb] = undefined;
7387 delete window[trans.cb];
7394 handleResponse : function(o, trans){
7396 this.destroyTrans(trans, true);
7399 result = trans.reader.readRecords(o);
7401 this.fireEvent("loadexception", this, o, trans.arg, e);
7402 trans.callback.call(trans.scope||window, null, trans.arg, false);
7405 this.fireEvent("load", this, o, trans.arg);
7406 trans.callback.call(trans.scope||window, result, trans.arg, true);
7410 handleFailure : function(trans){
7412 this.destroyTrans(trans, false);
7413 this.fireEvent("loadexception", this, null, trans.arg);
7414 trans.callback.call(trans.scope||window, null, trans.arg, false);
7418 * Ext JS Library 1.1.1
7419 * Copyright(c) 2006-2007, Ext JS, LLC.
7421 * Originally Released Under LGPL - original licence link has changed is not relivant.
7424 * <script type="text/javascript">
7428 * @class Roo.data.JsonReader
7429 * @extends Roo.data.DataReader
7430 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
7431 * based on mappings in a provided Roo.data.Record constructor.
7433 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
7434 * in the reply previously.
7439 var RecordDef = Roo.data.Record.create([
7440 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
7441 {name: 'occupation'} // This field will use "occupation" as the mapping.
7443 var myReader = new Roo.data.JsonReader({
7444 totalProperty: "results", // The property which contains the total dataset size (optional)
7445 root: "rows", // The property which contains an Array of row objects
7446 id: "id" // The property within each row object that provides an ID for the record (optional)
7450 * This would consume a JSON file like this:
7452 { 'results': 2, 'rows': [
7453 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
7454 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
7457 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
7458 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
7459 * paged from the remote server.
7460 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
7461 * @cfg {String} root name of the property which contains the Array of row objects.
7462 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
7464 * Create a new JsonReader
7465 * @param {Object} meta Metadata configuration options
7466 * @param {Object} recordType Either an Array of field definition objects,
7467 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
7469 Roo.data.JsonReader = function(meta, recordType){
7472 // set some defaults:
7474 totalProperty: 'total',
7475 successProperty : 'success',
7480 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
7482 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
7485 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
7486 * Used by Store query builder to append _requestMeta to params.
7489 metaFromRemote : false,
7491 * This method is only used by a DataProxy which has retrieved data from a remote server.
7492 * @param {Object} response The XHR object which contains the JSON data in its responseText.
7493 * @return {Object} data A data block which is used by an Roo.data.Store object as
7494 * a cache of Roo.data.Records.
7496 read : function(response){
7497 var json = response.responseText;
7499 var o = /* eval:var:o */ eval("("+json+")");
7501 throw {message: "JsonReader.read: Json object not found"};
7507 this.metaFromRemote = true;
7508 this.meta = o.metaData;
7509 this.recordType = Roo.data.Record.create(o.metaData.fields);
7510 this.onMetaChange(this.meta, this.recordType, o);
7512 return this.readRecords(o);
7515 // private function a store will implement
7516 onMetaChange : function(meta, recordType, o){
7523 simpleAccess: function(obj, subsc) {
7530 getJsonAccessor: function(){
7532 return function(expr) {
7534 return(re.test(expr))
7535 ? new Function("obj", "return obj." + expr)
7545 * Create a data block containing Roo.data.Records from an XML document.
7546 * @param {Object} o An object which contains an Array of row objects in the property specified
7547 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
7548 * which contains the total size of the dataset.
7549 * @return {Object} data A data block which is used by an Roo.data.Store object as
7550 * a cache of Roo.data.Records.
7552 readRecords : function(o){
7554 * After any data loads, the raw JSON data is available for further custom processing.
7558 var s = this.meta, Record = this.recordType,
7559 f = Record.prototype.fields, fi = f.items, fl = f.length;
7561 // Generate extraction functions for the totalProperty, the root, the id, and for each field
7563 if(s.totalProperty) {
7564 this.getTotal = this.getJsonAccessor(s.totalProperty);
7566 if(s.successProperty) {
7567 this.getSuccess = this.getJsonAccessor(s.successProperty);
7569 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
7571 var g = this.getJsonAccessor(s.id);
7572 this.getId = function(rec) {
7574 return (r === undefined || r === "") ? null : r;
7577 this.getId = function(){return null;};
7580 for(var jj = 0; jj < fl; jj++){
7582 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
7583 this.ef[jj] = this.getJsonAccessor(map);
7587 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
7588 if(s.totalProperty){
7589 var vt = parseInt(this.getTotal(o), 10);
7594 if(s.successProperty){
7595 var vs = this.getSuccess(o);
7596 if(vs === false || vs === 'false'){
7601 for(var i = 0; i < c; i++){
7604 var id = this.getId(n);
7605 for(var j = 0; j < fl; j++){
7607 var v = this.ef[j](n);
7609 Roo.log('missing convert for ' + f.name);
7613 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
7615 var record = new Record(values, id);
7617 records[i] = record;
7623 totalRecords : totalRecords
7628 * Ext JS Library 1.1.1
7629 * Copyright(c) 2006-2007, Ext JS, LLC.
7631 * Originally Released Under LGPL - original licence link has changed is not relivant.
7634 * <script type="text/javascript">
7638 * @class Roo.data.ArrayReader
7639 * @extends Roo.data.DataReader
7640 * Data reader class to create an Array of Roo.data.Record objects from an Array.
7641 * Each element of that Array represents a row of data fields. The
7642 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
7643 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
7647 var RecordDef = Roo.data.Record.create([
7648 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
7649 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
7651 var myReader = new Roo.data.ArrayReader({
7652 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
7656 * This would consume an Array like this:
7658 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
7660 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
7662 * Create a new JsonReader
7663 * @param {Object} meta Metadata configuration options.
7664 * @param {Object} recordType Either an Array of field definition objects
7665 * as specified to {@link Roo.data.Record#create},
7666 * or an {@link Roo.data.Record} object
7667 * created using {@link Roo.data.Record#create}.
7669 Roo.data.ArrayReader = function(meta, recordType){
7670 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
7673 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
7675 * Create a data block containing Roo.data.Records from an XML document.
7676 * @param {Object} o An Array of row objects which represents the dataset.
7677 * @return {Object} data A data block which is used by an Roo.data.Store object as
7678 * a cache of Roo.data.Records.
7680 readRecords : function(o){
7681 var sid = this.meta ? this.meta.id : null;
7682 var recordType = this.recordType, fields = recordType.prototype.fields;
7685 for(var i = 0; i < root.length; i++){
7688 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
7689 for(var j = 0, jlen = fields.length; j < jlen; j++){
7690 var f = fields.items[j];
7691 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
7692 var v = n[k] !== undefined ? n[k] : f.defaultValue;
7696 var record = new recordType(values, id);
7698 records[records.length] = record;
7702 totalRecords : records.length
7711 * @class Roo.bootstrap.ComboBox
7712 * @extends Roo.bootstrap.TriggerField
7713 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
7714 * @cfg {Boolean} append (true|false) default false
7716 * Create a new ComboBox.
7717 * @param {Object} config Configuration options
7719 Roo.bootstrap.ComboBox = function(config){
7720 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
7724 * Fires when the dropdown list is expanded
7725 * @param {Roo.bootstrap.ComboBox} combo This combo box
7730 * Fires when the dropdown list is collapsed
7731 * @param {Roo.bootstrap.ComboBox} combo This combo box
7735 * @event beforeselect
7736 * Fires before a list item is selected. Return false to cancel the selection.
7737 * @param {Roo.bootstrap.ComboBox} combo This combo box
7738 * @param {Roo.data.Record} record The data record returned from the underlying store
7739 * @param {Number} index The index of the selected item in the dropdown list
7741 'beforeselect' : true,
7744 * Fires when a list item is selected
7745 * @param {Roo.bootstrap.ComboBox} combo This combo box
7746 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
7747 * @param {Number} index The index of the selected item in the dropdown list
7751 * @event beforequery
7752 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
7753 * The event object passed has these properties:
7754 * @param {Roo.bootstrap.ComboBox} combo This combo box
7755 * @param {String} query The query
7756 * @param {Boolean} forceAll true to force "all" query
7757 * @param {Boolean} cancel true to cancel the query
7758 * @param {Object} e The query event object
7760 'beforequery': true,
7763 * Fires when the 'add' icon is pressed (add a listener to enable add button)
7764 * @param {Roo.bootstrap.ComboBox} combo This combo box
7769 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
7770 * @param {Roo.bootstrap.ComboBox} combo This combo box
7771 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
7776 * Fires when the remove value from the combobox array
7777 * @param {Roo.bootstrap.ComboBox} combo This combo box
7784 this.selectedIndex = -1;
7785 if(this.mode == 'local'){
7786 if(config.queryDelay === undefined){
7787 this.queryDelay = 10;
7789 if(config.minChars === undefined){
7795 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
7798 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
7799 * rendering into an Roo.Editor, defaults to false)
7802 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
7803 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
7806 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
7809 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
7810 * the dropdown list (defaults to undefined, with no header element)
7814 * @cfg {String/Roo.Template} tpl The template to use to render the output
7818 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
7820 listWidth: undefined,
7822 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
7823 * mode = 'remote' or 'text' if mode = 'local')
7825 displayField: undefined,
7827 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
7828 * mode = 'remote' or 'value' if mode = 'local').
7829 * Note: use of a valueField requires the user make a selection
7830 * in order for a value to be mapped.
7832 valueField: undefined,
7836 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
7837 * field's data value (defaults to the underlying DOM element's name)
7839 hiddenName: undefined,
7841 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
7845 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
7847 selectedClass: 'active',
7850 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
7854 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
7855 * anchor positions (defaults to 'tl-bl')
7857 listAlign: 'tl-bl?',
7859 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
7863 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
7864 * query specified by the allQuery config option (defaults to 'query')
7866 triggerAction: 'query',
7868 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
7869 * (defaults to 4, does not apply if editable = false)
7873 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
7874 * delay (typeAheadDelay) if it matches a known value (defaults to false)
7878 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
7879 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
7883 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
7884 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
7888 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
7889 * when editable = true (defaults to false)
7891 selectOnFocus:false,
7893 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
7895 queryParam: 'query',
7897 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
7898 * when mode = 'remote' (defaults to 'Loading...')
7900 loadingText: 'Loading...',
7902 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
7906 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
7910 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
7911 * traditional select (defaults to true)
7915 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
7919 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
7923 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
7924 * listWidth has a higher value)
7928 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
7929 * allow the user to set arbitrary text into the field (defaults to false)
7931 forceSelection:false,
7933 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
7934 * if typeAhead = true (defaults to 250)
7936 typeAheadDelay : 250,
7938 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
7939 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
7941 valueNotFoundText : undefined,
7943 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
7948 * @cfg {Boolean} disableClear Disable showing of clear button.
7950 disableClear : false,
7952 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
7954 alwaysQuery : false,
7957 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
7971 // element that contains real text value.. (when hidden is used..)
7974 initEvents: function(){
7977 throw "can not find store for combo";
7979 this.store = Roo.factory(this.store, Roo.data);
7983 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
7986 if(this.hiddenName){
7988 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
7990 this.hiddenField.dom.value =
7991 this.hiddenValue !== undefined ? this.hiddenValue :
7992 this.value !== undefined ? this.value : '';
7994 // prevent input submission
7995 this.el.dom.removeAttribute('name');
7996 this.hiddenField.dom.setAttribute('name', this.hiddenName);
8001 // this.el.dom.setAttribute('autocomplete', 'off');
8004 var cls = 'x-combo-list';
8005 this.list = this.el.select('ul.dropdown-menu',true).first();
8007 //this.list = new Roo.Layer({
8008 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
8011 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
8012 this.list.setWidth(lw);
8014 this.list.on('mouseover', this.onViewOver, this);
8015 this.list.on('mousemove', this.onViewMove, this);
8017 this.list.on('scroll', this.onViewScroll, this);
8020 this.list.swallowEvent('mousewheel');
8021 this.assetHeight = 0;
8024 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
8025 this.assetHeight += this.header.getHeight();
8028 this.innerList = this.list.createChild({cls:cls+'-inner'});
8029 this.innerList.on('mouseover', this.onViewOver, this);
8030 this.innerList.on('mousemove', this.onViewMove, this);
8031 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
8033 if(this.allowBlank && !this.pageSize && !this.disableClear){
8034 this.footer = this.list.createChild({cls:cls+'-ft'});
8035 this.pageTb = new Roo.Toolbar(this.footer);
8039 this.footer = this.list.createChild({cls:cls+'-ft'});
8040 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
8041 {pageSize: this.pageSize});
8045 if (this.pageTb && this.allowBlank && !this.disableClear) {
8047 this.pageTb.add(new Roo.Toolbar.Fill(), {
8048 cls: 'x-btn-icon x-btn-clear',
8054 _this.onSelect(false, -1);
8059 this.assetHeight += this.footer.getHeight();
8064 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
8067 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
8068 singleSelect:true, store: this.store, selectedClass: this.selectedClass
8070 //this.view.wrapEl.setDisplayed(false);
8071 this.view.on('click', this.onViewClick, this);
8075 this.store.on('beforeload', this.onBeforeLoad, this);
8076 this.store.on('load', this.onLoad, this);
8077 this.store.on('loadexception', this.onLoadException, this);
8080 this.resizer = new Roo.Resizable(this.list, {
8081 pinned:true, handles:'se'
8083 this.resizer.on('resize', function(r, w, h){
8084 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
8086 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
8087 this.restrictHeight();
8089 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
8093 this.editable = true;
8094 this.setEditable(false);
8099 if (typeof(this.events.add.listeners) != 'undefined') {
8101 this.addicon = this.wrap.createChild(
8102 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
8104 this.addicon.on('click', function(e) {
8105 this.fireEvent('add', this);
8108 if (typeof(this.events.edit.listeners) != 'undefined') {
8110 this.editicon = this.wrap.createChild(
8111 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
8113 this.editicon.setStyle('margin-left', '40px');
8115 this.editicon.on('click', function(e) {
8117 // we fire even if inothing is selected..
8118 this.fireEvent('edit', this, this.lastData );
8124 this.keyNav = new Roo.KeyNav(this.inputEl(), {
8126 this.inKeyMode = true;
8130 "down" : function(e){
8131 if(!this.isExpanded()){
8132 this.onTriggerClick();
8134 this.inKeyMode = true;
8139 "enter" : function(e){
8144 "esc" : function(e){
8148 "tab" : function(e){
8151 if(this.fireEvent("specialkey", this, e)){
8152 this.onViewClick(false);
8160 doRelay : function(foo, bar, hname){
8161 if(hname == 'down' || this.scope.isExpanded()){
8162 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
8171 this.queryDelay = Math.max(this.queryDelay || 10,
8172 this.mode == 'local' ? 10 : 250);
8175 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
8178 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
8180 if(this.editable !== false){
8181 this.inputEl().on("keyup", this.onKeyUp, this);
8183 if(this.forceSelection){
8184 this.on('blur', this.doForce, this);
8188 this.choices = this.el.select('ul.select2-choices', true).first();
8189 this.searchField = this.el.select('ul li.select2-search-field', true).first();
8193 onDestroy : function(){
8195 this.view.setStore(null);
8196 this.view.el.removeAllListeners();
8197 this.view.el.remove();
8198 this.view.purgeListeners();
8201 this.list.dom.innerHTML = '';
8204 this.store.un('beforeload', this.onBeforeLoad, this);
8205 this.store.un('load', this.onLoad, this);
8206 this.store.un('loadexception', this.onLoadException, this);
8208 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
8212 fireKey : function(e){
8213 if(e.isNavKeyPress() && !this.list.isVisible()){
8214 this.fireEvent("specialkey", this, e);
8219 onResize: function(w, h){
8220 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
8222 // if(typeof w != 'number'){
8223 // // we do not handle it!?!?
8226 // var tw = this.trigger.getWidth();
8227 // // tw += this.addicon ? this.addicon.getWidth() : 0;
8228 // // tw += this.editicon ? this.editicon.getWidth() : 0;
8230 // this.inputEl().setWidth( this.adjustWidth('input', x));
8232 // //this.trigger.setStyle('left', x+'px');
8234 // if(this.list && this.listWidth === undefined){
8235 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
8236 // this.list.setWidth(lw);
8237 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
8245 * Allow or prevent the user from directly editing the field text. If false is passed,
8246 * the user will only be able to select from the items defined in the dropdown list. This method
8247 * is the runtime equivalent of setting the 'editable' config option at config time.
8248 * @param {Boolean} value True to allow the user to directly edit the field text
8250 setEditable : function(value){
8251 if(value == this.editable){
8254 this.editable = value;
8256 this.inputEl().dom.setAttribute('readOnly', true);
8257 this.inputEl().on('mousedown', this.onTriggerClick, this);
8258 this.inputEl().addClass('x-combo-noedit');
8260 this.inputEl().dom.setAttribute('readOnly', false);
8261 this.inputEl().un('mousedown', this.onTriggerClick, this);
8262 this.inputEl().removeClass('x-combo-noedit');
8268 onBeforeLoad : function(combo,opts){
8273 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
8275 this.restrictHeight();
8276 this.selectedIndex = -1;
8280 onLoad : function(){
8282 this.hasQuery = false;
8288 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
8289 this.loading.hide();
8292 if(this.store.getCount() > 0){
8294 this.restrictHeight();
8295 if(this.lastQuery == this.allQuery){
8297 this.inputEl().dom.select();
8299 if(!this.selectByValue(this.value, true)){
8300 this.select(0, true);
8304 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
8305 this.taTask.delay(this.typeAheadDelay);
8309 this.onEmptyResults();
8315 onLoadException : function()
8317 this.hasQuery = false;
8319 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
8320 this.loading.hide();
8324 Roo.log(this.store.reader.jsonData);
8325 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
8327 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
8333 onTypeAhead : function(){
8334 if(this.store.getCount() > 0){
8335 var r = this.store.getAt(0);
8336 var newValue = r.data[this.displayField];
8337 var len = newValue.length;
8338 var selStart = this.getRawValue().length;
8340 if(selStart != len){
8341 this.setRawValue(newValue);
8342 this.selectText(selStart, newValue.length);
8348 onSelect : function(record, index){
8350 if(this.fireEvent('beforeselect', this, record, index) !== false){
8352 this.setFromData(index > -1 ? record.data : false);
8355 this.fireEvent('select', this, record, index);
8360 * Returns the currently selected field value or empty string if no value is set.
8361 * @return {String} value The selected value
8363 getValue : function(){
8366 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
8369 if(this.valueField){
8370 return typeof this.value != 'undefined' ? this.value : '';
8372 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
8377 * Clears any text/value currently set in the field
8379 clearValue : function(){
8380 if(this.hiddenField){
8381 this.hiddenField.dom.value = '';
8384 this.setRawValue('');
8385 this.lastSelectionText = '';
8390 * Sets the specified value into the field. If the value finds a match, the corresponding record text
8391 * will be displayed in the field. If the value does not match the data value of an existing item,
8392 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
8393 * Otherwise the field will be blank (although the value will still be set).
8394 * @param {String} value The value to match
8396 setValue : function(v){
8403 if(this.valueField){
8404 var r = this.findRecord(this.valueField, v);
8406 text = r.data[this.displayField];
8407 }else if(this.valueNotFoundText !== undefined){
8408 text = this.valueNotFoundText;
8411 this.lastSelectionText = text;
8412 if(this.hiddenField){
8413 this.hiddenField.dom.value = v;
8415 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
8419 * @property {Object} the last set data for the element
8424 * Sets the value of the field based on a object which is related to the record format for the store.
8425 * @param {Object} value the value to set as. or false on reset?
8427 setFromData : function(o){
8434 var dv = ''; // display value
8435 var vv = ''; // value value..
8437 if (this.displayField) {
8438 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
8440 // this is an error condition!!!
8441 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
8444 if(this.valueField){
8445 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
8448 if(this.hiddenField){
8449 this.hiddenField.dom.value = vv;
8451 this.lastSelectionText = dv;
8452 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
8456 // no hidden field.. - we store the value in 'value', but still display
8457 // display field!!!!
8458 this.lastSelectionText = dv;
8459 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
8466 // overridden so that last data is reset..
8467 this.setValue(this.originalValue);
8468 this.clearInvalid();
8469 this.lastData = false;
8471 this.view.clearSelections();
8475 findRecord : function(prop, value){
8477 if(this.store.getCount() > 0){
8478 this.store.each(function(r){
8479 if(r.data[prop] == value){
8491 // returns hidden if it's set..
8492 if (!this.rendered) {return ''};
8493 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
8497 onViewMove : function(e, t){
8498 this.inKeyMode = false;
8502 onViewOver : function(e, t){
8503 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
8506 var item = this.view.findItemFromChild(t);
8508 var index = this.view.indexOf(item);
8509 this.select(index, false);
8514 onViewClick : function(doFocus)
8516 var index = this.view.getSelectedIndexes()[0];
8517 var r = this.store.getAt(index);
8519 this.onSelect(r, index);
8521 if(doFocus !== false && !this.blockFocus){
8522 this.inputEl().focus();
8527 restrictHeight : function(){
8528 //this.innerList.dom.style.height = '';
8529 //var inner = this.innerList.dom;
8530 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
8531 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
8532 //this.list.beginUpdate();
8533 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
8534 this.list.alignTo(this.inputEl(), this.listAlign);
8535 //this.list.endUpdate();
8539 onEmptyResults : function(){
8544 * Returns true if the dropdown list is expanded, else false.
8546 isExpanded : function(){
8547 return this.list.isVisible();
8551 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
8552 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
8553 * @param {String} value The data value of the item to select
8554 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
8555 * selected item if it is not currently in view (defaults to true)
8556 * @return {Boolean} True if the value matched an item in the list, else false
8558 selectByValue : function(v, scrollIntoView){
8559 if(v !== undefined && v !== null){
8560 var r = this.findRecord(this.valueField || this.displayField, v);
8562 this.select(this.store.indexOf(r), scrollIntoView);
8570 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
8571 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
8572 * @param {Number} index The zero-based index of the list item to select
8573 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
8574 * selected item if it is not currently in view (defaults to true)
8576 select : function(index, scrollIntoView){
8577 this.selectedIndex = index;
8578 this.view.select(index);
8579 if(scrollIntoView !== false){
8580 var el = this.view.getNode(index);
8582 //this.innerList.scrollChildIntoView(el, false);
8589 selectNext : function(){
8590 var ct = this.store.getCount();
8592 if(this.selectedIndex == -1){
8594 }else if(this.selectedIndex < ct-1){
8595 this.select(this.selectedIndex+1);
8601 selectPrev : function(){
8602 var ct = this.store.getCount();
8604 if(this.selectedIndex == -1){
8606 }else if(this.selectedIndex != 0){
8607 this.select(this.selectedIndex-1);
8613 onKeyUp : function(e){
8614 if(this.editable !== false && !e.isSpecialKey()){
8615 this.lastKey = e.getKey();
8616 this.dqTask.delay(this.queryDelay);
8621 validateBlur : function(){
8622 return !this.list || !this.list.isVisible();
8626 initQuery : function(){
8627 this.doQuery(this.getRawValue());
8631 doForce : function(){
8632 if(this.el.dom.value.length > 0){
8634 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
8640 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
8641 * query allowing the query action to be canceled if needed.
8642 * @param {String} query The SQL query to execute
8643 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
8644 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
8645 * saved in the current store (defaults to false)
8647 doQuery : function(q, forceAll){
8649 if(q === undefined || q === null){
8658 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
8663 forceAll = qe.forceAll;
8664 if(forceAll === true || (q.length >= this.minChars)){
8666 this.hasQuery = true;
8668 if(this.lastQuery != q || this.alwaysQuery){
8670 if(this.mode == 'local'){
8671 this.selectedIndex = -1;
8673 this.store.clearFilter();
8675 this.store.filter(this.displayField, q);
8679 this.store.baseParams[this.queryParam] = q;
8681 var options = {params : this.getParams(q)};
8685 options.params.start = this.page * this.pageSize;
8688 this.store.load(options);
8692 this.selectedIndex = -1;
8697 this.loadNext = false;
8701 getParams : function(q){
8703 //p[this.queryParam] = q;
8707 p.limit = this.pageSize;
8713 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
8715 collapse : function(){
8716 if(!this.isExpanded()){
8721 Roo.get(document).un('mousedown', this.collapseIf, this);
8722 Roo.get(document).un('mousewheel', this.collapseIf, this);
8723 if (!this.editable) {
8724 Roo.get(document).un('keydown', this.listKeyPress, this);
8726 this.fireEvent('collapse', this);
8730 collapseIf : function(e){
8731 var in_combo = e.within(this.el);
8732 var in_list = e.within(this.list);
8734 if (in_combo || in_list) {
8735 //e.stopPropagation();
8744 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
8746 expand : function(){
8748 if(this.isExpanded() || !this.hasFocus){
8752 this.list.alignTo(this.inputEl(), this.listAlign);
8754 Roo.get(document).on('mousedown', this.collapseIf, this);
8755 Roo.get(document).on('mousewheel', this.collapseIf, this);
8756 if (!this.editable) {
8757 Roo.get(document).on('keydown', this.listKeyPress, this);
8760 this.fireEvent('expand', this);
8764 // Implements the default empty TriggerField.onTriggerClick function
8765 onTriggerClick : function()
8767 Roo.log('trigger click');
8774 this.loadNext = false;
8776 if(this.isExpanded()){
8778 if (!this.blockFocus) {
8779 this.inputEl().focus();
8783 this.hasFocus = true;
8784 if(this.triggerAction == 'all') {
8785 this.doQuery(this.allQuery, true);
8787 this.doQuery(this.getRawValue());
8789 if (!this.blockFocus) {
8790 this.inputEl().focus();
8794 listKeyPress : function(e)
8796 //Roo.log('listkeypress');
8797 // scroll to first matching element based on key pres..
8798 if (e.isSpecialKey()) {
8801 var k = String.fromCharCode(e.getKey()).toUpperCase();
8804 var csel = this.view.getSelectedNodes();
8805 var cselitem = false;
8807 var ix = this.view.indexOf(csel[0]);
8808 cselitem = this.store.getAt(ix);
8809 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
8815 this.store.each(function(v) {
8817 // start at existing selection.
8818 if (cselitem.id == v.id) {
8824 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
8825 match = this.store.indexOf(v);
8831 if (match === false) {
8832 return true; // no more action?
8835 this.view.select(match);
8836 var sn = Roo.get(this.view.getSelectedNodes()[0])
8837 //sn.scrollIntoView(sn.dom.parentNode, false);
8840 onViewScroll : function(e, t){
8842 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
8846 this.hasQuery = true;
8848 this.loading = this.list.select('.loading', true).first();
8850 if(this.loading === null){
8851 this.list.createChild({
8853 cls: 'loading select2-more-results select2-active',
8854 html: 'Loading more results...'
8857 this.loading = this.list.select('.loading', true).first();
8859 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
8861 this.loading.hide();
8864 this.loading.show();
8869 this.loadNext = true;
8871 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
8876 addItem : function(o)
8878 var dv = ''; // display value
8880 if (this.displayField) {
8881 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
8883 // this is an error condition!!!
8884 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
8891 var choice = this.choices.createChild({
8893 cls: 'select2-search-choice',
8902 cls: 'select2-search-choice-close',
8907 }, this.searchField);
8909 var close = choice.select('a.select2-search-choice-close', true).first()
8911 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
8918 this.inputEl().dom.value = '';
8922 onRemoveItem : function(e, _self, o)
8924 Roo.log('remove item');
8925 var index = this.item.indexOf(o.data) * 1;
8928 Roo.log('not this item?!');
8932 this.item.splice(index, 1);
8937 this.fireEvent('remove', this);
8941 syncValue : function()
8943 if(!this.item.length){
8950 Roo.each(this.item, function(i){
8951 if(_this.valueField){
8952 value.push(i[_this.valueField]);
8959 this.value = value.join(',');
8961 if(this.hiddenField){
8962 this.hiddenField.dom.value = this.value;
8966 clearItem : function()
8974 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
8984 * @cfg {Boolean} grow
8988 * @cfg {Number} growMin
8992 * @cfg {Number} growMax
9002 * Ext JS Library 1.1.1
9003 * Copyright(c) 2006-2007, Ext JS, LLC.
9005 * Originally Released Under LGPL - original licence link has changed is not relivant.
9008 * <script type="text/javascript">
9013 * @extends Roo.util.Observable
9014 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
9015 * This class also supports single and multi selection modes. <br>
9016 * Create a data model bound view:
9018 var store = new Roo.data.Store(...);
9020 var view = new Roo.View({
9022 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
9025 selectedClass: "ydataview-selected",
9029 // listen for node click?
9030 view.on("click", function(vw, index, node, e){
9031 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9035 dataModel.load("foobar.xml");
9037 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
9039 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
9040 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
9042 * Note: old style constructor is still suported (container, template, config)
9046 * @param {Object} config The config object
9049 Roo.View = function(config, depreciated_tpl, depreciated_config){
9051 if (typeof(depreciated_tpl) == 'undefined') {
9052 // new way.. - universal constructor.
9053 Roo.apply(this, config);
9054 this.el = Roo.get(this.el);
9057 this.el = Roo.get(config);
9058 this.tpl = depreciated_tpl;
9059 Roo.apply(this, depreciated_config);
9061 this.wrapEl = this.el.wrap().wrap();
9062 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
9065 if(typeof(this.tpl) == "string"){
9066 this.tpl = new Roo.Template(this.tpl);
9068 // support xtype ctors..
9069 this.tpl = new Roo.factory(this.tpl, Roo);
9081 * @event beforeclick
9082 * Fires before a click is processed. Returns false to cancel the default action.
9083 * @param {Roo.View} this
9084 * @param {Number} index The index of the target node
9085 * @param {HTMLElement} node The target node
9086 * @param {Roo.EventObject} e The raw event object
9088 "beforeclick" : true,
9091 * Fires when a template node is clicked.
9092 * @param {Roo.View} this
9093 * @param {Number} index The index of the target node
9094 * @param {HTMLElement} node The target node
9095 * @param {Roo.EventObject} e The raw event object
9100 * Fires when a template node is double clicked.
9101 * @param {Roo.View} this
9102 * @param {Number} index The index of the target node
9103 * @param {HTMLElement} node The target node
9104 * @param {Roo.EventObject} e The raw event object
9108 * @event contextmenu
9109 * Fires when a template node is right clicked.
9110 * @param {Roo.View} this
9111 * @param {Number} index The index of the target node
9112 * @param {HTMLElement} node The target node
9113 * @param {Roo.EventObject} e The raw event object
9115 "contextmenu" : true,
9117 * @event selectionchange
9118 * Fires when the selected nodes change.
9119 * @param {Roo.View} this
9120 * @param {Array} selections Array of the selected nodes
9122 "selectionchange" : true,
9125 * @event beforeselect
9126 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
9127 * @param {Roo.View} this
9128 * @param {HTMLElement} node The node to be selected
9129 * @param {Array} selections Array of currently selected nodes
9131 "beforeselect" : true,
9133 * @event preparedata
9134 * Fires on every row to render, to allow you to change the data.
9135 * @param {Roo.View} this
9136 * @param {Object} data to be rendered (change this)
9138 "preparedata" : true
9146 "click": this.onClick,
9147 "dblclick": this.onDblClick,
9148 "contextmenu": this.onContextMenu,
9152 this.selections = [];
9154 this.cmp = new Roo.CompositeElementLite([]);
9156 this.store = Roo.factory(this.store, Roo.data);
9157 this.setStore(this.store, true);
9160 if ( this.footer && this.footer.xtype) {
9162 var fctr = this.wrapEl.appendChild(document.createElement("div"));
9164 this.footer.dataSource = this.store
9165 this.footer.container = fctr;
9166 this.footer = Roo.factory(this.footer, Roo);
9167 fctr.insertFirst(this.el);
9169 // this is a bit insane - as the paging toolbar seems to detach the el..
9170 // dom.parentNode.parentNode.parentNode
9171 // they get detached?
9175 Roo.View.superclass.constructor.call(this);
9180 Roo.extend(Roo.View, Roo.util.Observable, {
9183 * @cfg {Roo.data.Store} store Data store to load data from.
9188 * @cfg {String|Roo.Element} el The container element.
9193 * @cfg {String|Roo.Template} tpl The template used by this View
9197 * @cfg {String} dataName the named area of the template to use as the data area
9198 * Works with domtemplates roo-name="name"
9202 * @cfg {String} selectedClass The css class to add to selected nodes
9204 selectedClass : "x-view-selected",
9206 * @cfg {String} emptyText The empty text to show when nothing is loaded.
9211 * @cfg {String} text to display on mask (default Loading)
9215 * @cfg {Boolean} multiSelect Allow multiple selection
9217 multiSelect : false,
9219 * @cfg {Boolean} singleSelect Allow single selection
9221 singleSelect: false,
9224 * @cfg {Boolean} toggleSelect - selecting
9226 toggleSelect : false,
9229 * Returns the element this view is bound to.
9230 * @return {Roo.Element}
9239 * Refreshes the view. - called by datachanged on the store. - do not call directly.
9241 refresh : function(){
9245 // if we are using something like 'domtemplate', then
9246 // the what gets used is:
9247 // t.applySubtemplate(NAME, data, wrapping data..)
9248 // the outer template then get' applied with
9249 // the store 'extra data'
9250 // and the body get's added to the
9251 // roo-name="data" node?
9252 // <span class='roo-tpl-{name}'></span> ?????
9256 this.clearSelections();
9259 var records = this.store.getRange();
9260 if(records.length < 1) {
9262 // is this valid?? = should it render a template??
9264 this.el.update(this.emptyText);
9268 if (this.dataName) {
9269 this.el.update(t.apply(this.store.meta)); //????
9270 el = this.el.child('.roo-tpl-' + this.dataName);
9273 for(var i = 0, len = records.length; i < len; i++){
9274 var data = this.prepareData(records[i].data, i, records[i]);
9275 this.fireEvent("preparedata", this, data, i, records[i]);
9276 html[html.length] = Roo.util.Format.trim(
9278 t.applySubtemplate(this.dataName, data, this.store.meta) :
9285 el.update(html.join(""));
9286 this.nodes = el.dom.childNodes;
9287 this.updateIndexes(0);
9292 * Function to override to reformat the data that is sent to
9293 * the template for each node.
9294 * DEPRICATED - use the preparedata event handler.
9295 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
9296 * a JSON object for an UpdateManager bound view).
9298 prepareData : function(data, index, record)
9300 this.fireEvent("preparedata", this, data, index, record);
9304 onUpdate : function(ds, record){
9305 Roo.log('on update');
9306 this.clearSelections();
9307 var index = this.store.indexOf(record);
9308 var n = this.nodes[index];
9309 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
9310 n.parentNode.removeChild(n);
9311 this.updateIndexes(index, index);
9317 onAdd : function(ds, records, index)
9319 Roo.log(['on Add', ds, records, index] );
9320 this.clearSelections();
9321 if(this.nodes.length == 0){
9325 var n = this.nodes[index];
9326 for(var i = 0, len = records.length; i < len; i++){
9327 var d = this.prepareData(records[i].data, i, records[i]);
9329 this.tpl.insertBefore(n, d);
9332 this.tpl.append(this.el, d);
9335 this.updateIndexes(index);
9338 onRemove : function(ds, record, index){
9339 Roo.log('onRemove');
9340 this.clearSelections();
9341 var el = this.dataName ?
9342 this.el.child('.roo-tpl-' + this.dataName) :
9345 el.dom.removeChild(this.nodes[index]);
9346 this.updateIndexes(index);
9350 * Refresh an individual node.
9351 * @param {Number} index
9353 refreshNode : function(index){
9354 this.onUpdate(this.store, this.store.getAt(index));
9357 updateIndexes : function(startIndex, endIndex){
9358 var ns = this.nodes;
9359 startIndex = startIndex || 0;
9360 endIndex = endIndex || ns.length - 1;
9361 for(var i = startIndex; i <= endIndex; i++){
9362 ns[i].nodeIndex = i;
9367 * Changes the data store this view uses and refresh the view.
9368 * @param {Store} store
9370 setStore : function(store, initial){
9371 if(!initial && this.store){
9372 this.store.un("datachanged", this.refresh);
9373 this.store.un("add", this.onAdd);
9374 this.store.un("remove", this.onRemove);
9375 this.store.un("update", this.onUpdate);
9376 this.store.un("clear", this.refresh);
9377 this.store.un("beforeload", this.onBeforeLoad);
9378 this.store.un("load", this.onLoad);
9379 this.store.un("loadexception", this.onLoad);
9383 store.on("datachanged", this.refresh, this);
9384 store.on("add", this.onAdd, this);
9385 store.on("remove", this.onRemove, this);
9386 store.on("update", this.onUpdate, this);
9387 store.on("clear", this.refresh, this);
9388 store.on("beforeload", this.onBeforeLoad, this);
9389 store.on("load", this.onLoad, this);
9390 store.on("loadexception", this.onLoad, this);
9398 * onbeforeLoad - masks the loading area.
9401 onBeforeLoad : function(store,opts)
9403 Roo.log('onBeforeLoad');
9407 this.el.mask(this.mask ? this.mask : "Loading" );
9409 onLoad : function ()
9416 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
9417 * @param {HTMLElement} node
9418 * @return {HTMLElement} The template node
9420 findItemFromChild : function(node){
9421 var el = this.dataName ?
9422 this.el.child('.roo-tpl-' + this.dataName,true) :
9425 if(!node || node.parentNode == el){
9428 var p = node.parentNode;
9429 while(p && p != el){
9430 if(p.parentNode == el){
9439 onClick : function(e){
9440 var item = this.findItemFromChild(e.getTarget());
9442 var index = this.indexOf(item);
9443 if(this.onItemClick(item, index, e) !== false){
9444 this.fireEvent("click", this, index, item, e);
9447 this.clearSelections();
9452 onContextMenu : function(e){
9453 var item = this.findItemFromChild(e.getTarget());
9455 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
9460 onDblClick : function(e){
9461 var item = this.findItemFromChild(e.getTarget());
9463 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
9467 onItemClick : function(item, index, e)
9469 if(this.fireEvent("beforeclick", this, index, item, e) === false){
9472 if (this.toggleSelect) {
9473 var m = this.isSelected(item) ? 'unselect' : 'select';
9476 _t[m](item, true, false);
9479 if(this.multiSelect || this.singleSelect){
9480 if(this.multiSelect && e.shiftKey && this.lastSelection){
9481 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
9483 this.select(item, this.multiSelect && e.ctrlKey);
9484 this.lastSelection = item;
9492 * Get the number of selected nodes.
9495 getSelectionCount : function(){
9496 return this.selections.length;
9500 * Get the currently selected nodes.
9501 * @return {Array} An array of HTMLElements
9503 getSelectedNodes : function(){
9504 return this.selections;
9508 * Get the indexes of the selected nodes.
9511 getSelectedIndexes : function(){
9512 var indexes = [], s = this.selections;
9513 for(var i = 0, len = s.length; i < len; i++){
9514 indexes.push(s[i].nodeIndex);
9520 * Clear all selections
9521 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
9523 clearSelections : function(suppressEvent){
9524 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
9525 this.cmp.elements = this.selections;
9526 this.cmp.removeClass(this.selectedClass);
9527 this.selections = [];
9529 this.fireEvent("selectionchange", this, this.selections);
9535 * Returns true if the passed node is selected
9536 * @param {HTMLElement/Number} node The node or node index
9539 isSelected : function(node){
9540 var s = this.selections;
9544 node = this.getNode(node);
9545 return s.indexOf(node) !== -1;
9550 * @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
9551 * @param {Boolean} keepExisting (optional) true to keep existing selections
9552 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
9554 select : function(nodeInfo, keepExisting, suppressEvent){
9555 if(nodeInfo instanceof Array){
9557 this.clearSelections(true);
9559 for(var i = 0, len = nodeInfo.length; i < len; i++){
9560 this.select(nodeInfo[i], true, true);
9564 var node = this.getNode(nodeInfo);
9565 if(!node || this.isSelected(node)){
9566 return; // already selected.
9569 this.clearSelections(true);
9571 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
9572 Roo.fly(node).addClass(this.selectedClass);
9573 this.selections.push(node);
9575 this.fireEvent("selectionchange", this, this.selections);
9583 * @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
9584 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
9585 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
9587 unselect : function(nodeInfo, keepExisting, suppressEvent)
9589 if(nodeInfo instanceof Array){
9590 Roo.each(this.selections, function(s) {
9591 this.unselect(s, nodeInfo);
9595 var node = this.getNode(nodeInfo);
9596 if(!node || !this.isSelected(node)){
9597 Roo.log("not selected");
9598 return; // not selected.
9602 Roo.each(this.selections, function(s) {
9604 Roo.fly(node).removeClass(this.selectedClass);
9611 this.selections= ns;
9612 this.fireEvent("selectionchange", this, this.selections);
9616 * Gets a template node.
9617 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9618 * @return {HTMLElement} The node or null if it wasn't found
9620 getNode : function(nodeInfo){
9621 if(typeof nodeInfo == "string"){
9622 return document.getElementById(nodeInfo);
9623 }else if(typeof nodeInfo == "number"){
9624 return this.nodes[nodeInfo];
9630 * Gets a range template nodes.
9631 * @param {Number} startIndex
9632 * @param {Number} endIndex
9633 * @return {Array} An array of nodes
9635 getNodes : function(start, end){
9636 var ns = this.nodes;
9638 end = typeof end == "undefined" ? ns.length - 1 : end;
9641 for(var i = start; i <= end; i++){
9645 for(var i = start; i >= end; i--){
9653 * Finds the index of the passed node
9654 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9655 * @return {Number} The index of the node or -1
9657 indexOf : function(node){
9658 node = this.getNode(node);
9659 if(typeof node.nodeIndex == "number"){
9660 return node.nodeIndex;
9662 var ns = this.nodes;
9663 for(var i = 0, len = ns.length; i < len; i++){
9674 * based on jquery fullcalendar
9678 Roo.bootstrap = Roo.bootstrap || {};
9680 * @class Roo.bootstrap.Calendar
9681 * @extends Roo.bootstrap.Component
9682 * Bootstrap Calendar class
9683 * @cfg {Boolean} loadMask (true|false) default false
9686 * Create a new Container
9687 * @param {Object} config The config object
9692 Roo.bootstrap.Calendar = function(config){
9693 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
9697 * Fires when a date is selected
9698 * @param {DatePicker} this
9699 * @param {Date} date The selected date
9703 * @event monthchange
9704 * Fires when the displayed month changes
9705 * @param {DatePicker} this
9706 * @param {Date} date The selected month
9708 'monthchange': true,
9711 * Fires when mouse over an event
9712 * @param {Calendar} this
9713 * @param {event} Event
9718 * Fires when the mouse leaves an
9719 * @param {Calendar} this
9725 * Fires when the mouse click an
9726 * @param {Calendar} this
9735 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
9738 * @cfg {Number} startDay
9739 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
9745 getAutoCreate : function(){
9748 var fc_button = function(name, corner, style, content ) {
9749 return Roo.apply({},{
9751 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
9753 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
9756 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
9764 style : 'width:100%',
9771 cls : 'fc-header-left',
9773 fc_button('prev', 'left', 'arrow', '‹' ),
9774 fc_button('next', 'right', 'arrow', '›' ),
9775 { tag: 'span', cls: 'fc-header-space' },
9776 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
9784 cls : 'fc-header-center',
9788 cls: 'fc-header-title',
9791 html : 'month / year'
9799 cls : 'fc-header-right',
9801 /* fc_button('month', 'left', '', 'month' ),
9802 fc_button('week', '', '', 'week' ),
9803 fc_button('day', 'right', '', 'day' )
9815 var cal_heads = function() {
9817 // fixme - handle this.
9819 for (var i =0; i < Date.dayNames.length; i++) {
9820 var d = Date.dayNames[i];
9823 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
9824 html : d.substring(0,3)
9828 ret[0].cls += ' fc-first';
9829 ret[6].cls += ' fc-last';
9832 var cal_cell = function(n) {
9835 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
9840 cls: 'fc-day-number',
9844 cls: 'fc-day-content',
9848 style: 'position: relative;' // height: 17px;
9860 var cal_rows = function() {
9863 for (var r = 0; r < 6; r++) {
9870 for (var i =0; i < Date.dayNames.length; i++) {
9871 var d = Date.dayNames[i];
9872 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
9875 row.cn[0].cls+=' fc-first';
9876 row.cn[0].cn[0].style = 'min-height:90px';
9877 row.cn[6].cls+=' fc-last';
9881 ret[0].cls += ' fc-first';
9882 ret[4].cls += ' fc-prev-last';
9883 ret[5].cls += ' fc-last';
9890 cls: 'fc-border-separate',
9891 style : 'width:100%',
9899 cls : 'fc-first fc-last',
9918 style : "position: relative;",
9921 cls : 'fc-view fc-view-month fc-grid',
9922 style : 'position: relative',
9923 unselectable : 'on',
9926 cls : 'fc-event-container',
9927 style : 'position:absolute;z-index:8;top:0;left:0;'
9945 initEvents : function()
9948 throw "can not find store for calendar";
9954 style: "text-align:center",
9958 style: "background-color:white;width:50%;margin:250 auto",
9962 src: rootURL + '/roojs1/images/ux/lightbox/loading.gif'
9973 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
9975 var size = this.el.select('.fc-content', true).first().getSize();
9976 this.maskEl.setSize(size.width, size.height);
9977 this.maskEl.enableDisplayMode("block");
9982 this.store = Roo.factory(this.store, Roo.data);
9983 this.store.on('load', this.onLoad, this);
9984 this.store.on('beforeload', this.onBeforeLoad, this);
9988 this.cells = this.el.select('.fc-day',true);
9989 //Roo.log(this.cells);
9990 this.textNodes = this.el.query('.fc-day-number');
9991 this.cells.addClassOnOver('fc-state-hover');
9993 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
9994 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
9995 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
9996 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
9998 this.on('monthchange', this.onMonthChange, this);
10000 this.update(new Date().clearTime());
10003 resize : function() {
10004 var sz = this.el.getSize();
10006 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
10007 this.el.select('.fc-day-content div',true).setHeight(34);
10012 showPrevMonth : function(e){
10013 this.update(this.activeDate.add("mo", -1));
10015 showToday : function(e){
10016 this.update(new Date().clearTime());
10019 showNextMonth : function(e){
10020 this.update(this.activeDate.add("mo", 1));
10024 showPrevYear : function(){
10025 this.update(this.activeDate.add("y", -1));
10029 showNextYear : function(){
10030 this.update(this.activeDate.add("y", 1));
10035 update : function(date)
10037 var vd = this.activeDate;
10038 this.activeDate = date;
10039 // if(vd && this.el){
10040 // var t = date.getTime();
10041 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
10042 // Roo.log('using add remove');
10044 // this.fireEvent('monthchange', this, date);
10046 // this.cells.removeClass("fc-state-highlight");
10047 // this.cells.each(function(c){
10048 // if(c.dateValue == t){
10049 // c.addClass("fc-state-highlight");
10050 // setTimeout(function(){
10051 // try{c.dom.firstChild.focus();}catch(e){}
10061 var days = date.getDaysInMonth();
10063 var firstOfMonth = date.getFirstDateOfMonth();
10064 var startingPos = firstOfMonth.getDay()-this.startDay;
10066 if(startingPos < this.startDay){
10070 var pm = date.add(Date.MONTH, -1);
10071 var prevStart = pm.getDaysInMonth()-startingPos;
10073 this.cells = this.el.select('.fc-day',true);
10074 this.textNodes = this.el.query('.fc-day-number');
10075 this.cells.addClassOnOver('fc-state-hover');
10077 var cells = this.cells.elements;
10078 var textEls = this.textNodes;
10080 Roo.each(cells, function(cell){
10081 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
10084 days += startingPos;
10086 // convert everything to numbers so it's fast
10087 var day = 86400000;
10088 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
10091 //Roo.log(prevStart);
10093 var today = new Date().clearTime().getTime();
10094 var sel = date.clearTime().getTime();
10095 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
10096 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
10097 var ddMatch = this.disabledDatesRE;
10098 var ddText = this.disabledDatesText;
10099 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
10100 var ddaysText = this.disabledDaysText;
10101 var format = this.format;
10103 var setCellClass = function(cal, cell){
10105 //Roo.log('set Cell Class');
10107 var t = d.getTime();
10111 cell.dateValue = t;
10113 cell.className += " fc-today";
10114 cell.className += " fc-state-highlight";
10115 cell.title = cal.todayText;
10118 // disable highlight in other month..
10119 //cell.className += " fc-state-highlight";
10124 cell.className = " fc-state-disabled";
10125 cell.title = cal.minText;
10129 cell.className = " fc-state-disabled";
10130 cell.title = cal.maxText;
10134 if(ddays.indexOf(d.getDay()) != -1){
10135 cell.title = ddaysText;
10136 cell.className = " fc-state-disabled";
10139 if(ddMatch && format){
10140 var fvalue = d.dateFormat(format);
10141 if(ddMatch.test(fvalue)){
10142 cell.title = ddText.replace("%0", fvalue);
10143 cell.className = " fc-state-disabled";
10147 if (!cell.initialClassName) {
10148 cell.initialClassName = cell.dom.className;
10151 cell.dom.className = cell.initialClassName + ' ' + cell.className;
10156 for(; i < startingPos; i++) {
10157 textEls[i].innerHTML = (++prevStart);
10158 d.setDate(d.getDate()+1);
10160 cells[i].className = "fc-past fc-other-month";
10161 setCellClass(this, cells[i]);
10166 for(; i < days; i++){
10167 intDay = i - startingPos + 1;
10168 textEls[i].innerHTML = (intDay);
10169 d.setDate(d.getDate()+1);
10171 cells[i].className = ''; // "x-date-active";
10172 setCellClass(this, cells[i]);
10176 for(; i < 42; i++) {
10177 textEls[i].innerHTML = (++extraDays);
10178 d.setDate(d.getDate()+1);
10180 cells[i].className = "fc-future fc-other-month";
10181 setCellClass(this, cells[i]);
10184 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
10186 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
10188 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
10189 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
10191 if(totalRows != 6){
10192 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
10193 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
10196 this.fireEvent('monthchange', this, date);
10200 if(!this.internalRender){
10201 var main = this.el.dom.firstChild;
10202 var w = main.offsetWidth;
10203 this.el.setWidth(w + this.el.getBorderWidth("lr"));
10204 Roo.fly(main).setWidth(w);
10205 this.internalRender = true;
10206 // opera does not respect the auto grow header center column
10207 // then, after it gets a width opera refuses to recalculate
10208 // without a second pass
10209 if(Roo.isOpera && !this.secondPass){
10210 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
10211 this.secondPass = true;
10212 this.update.defer(10, this, [date]);
10219 findCell : function(dt) {
10220 dt = dt.clearTime().getTime();
10222 this.cells.each(function(c){
10223 //Roo.log("check " +c.dateValue + '?=' + dt);
10224 if(c.dateValue == dt){
10234 findCells : function(ev) {
10235 var s = ev.start.clone().clearTime().getTime();
10237 var e= ev.end.clone().clearTime().getTime();
10240 this.cells.each(function(c){
10241 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
10243 if(c.dateValue > e){
10246 if(c.dateValue < s){
10255 findBestRow: function(cells)
10259 for (var i =0 ; i < cells.length;i++) {
10260 ret = Math.max(cells[i].rows || 0,ret);
10267 addItem : function(ev)
10269 // look for vertical location slot in
10270 var cells = this.findCells(ev);
10272 ev.row = this.findBestRow(cells);
10274 // work out the location.
10278 for(var i =0; i < cells.length; i++) {
10286 if (crow.start.getY() == cells[i].getY()) {
10288 crow.end = cells[i];
10304 for (var i = 0; i < cells.length;i++) {
10305 cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
10309 this.calevents.push(ev);
10312 clearEvents: function() {
10314 if(!this.calevents){
10318 Roo.each(this.cells.elements, function(c){
10322 Roo.each(this.calevents, function(e) {
10323 Roo.each(e.els, function(el) {
10324 el.un('mouseenter' ,this.onEventEnter, this);
10325 el.un('mouseleave' ,this.onEventLeave, this);
10332 renderEvents: function()
10334 // first make sure there is enough space..
10336 this.cells.each(function(c) {
10338 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.rows * 20));
10341 for (var e = 0; e < this.calevents.length; e++) {
10342 var ev = this.calevents[e];
10343 var cells = ev.cells;
10344 var rows = ev.rows;
10346 for(var i =0; i < rows.length; i++) {
10349 // how many rows should it span..
10352 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
10353 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
10355 unselectable : "on",
10358 cls: 'fc-event-inner',
10362 // cls: 'fc-event-time',
10363 // html : cells.length > 1 ? '' : ev.time
10367 cls: 'fc-event-title',
10368 html : String.format('{0}', ev.title)
10375 cls: 'ui-resizable-handle ui-resizable-e',
10376 html : '  '
10382 cfg.cls += ' fc-event-start';
10384 if ((i+1) == rows.length) {
10385 cfg.cls += ' fc-event-end';
10388 var ctr = this.el.select('.fc-event-container',true).first();
10389 var cg = ctr.createChild(cfg);
10391 cg.on('mouseenter' ,this.onEventEnter, this, ev);
10392 cg.on('mouseleave' ,this.onEventLeave, this, ev);
10393 cg.on('click', this.onEventClick, this, ev);
10397 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
10398 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
10400 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
10401 cg.setWidth(ebox.right - sbox.x -2);
10409 onEventEnter: function (e, el,event,d) {
10410 this.fireEvent('evententer', this, el, event);
10413 onEventLeave: function (e, el,event,d) {
10414 this.fireEvent('eventleave', this, el, event);
10417 onEventClick: function (e, el,event,d) {
10418 this.fireEvent('eventclick', this, el, event);
10421 onMonthChange: function () {
10425 onLoad: function ()
10427 this.calevents = [];
10430 if(this.store.getCount() > 0){
10431 this.store.data.each(function(d){
10434 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
10435 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
10436 time : d.data.start_time,
10437 title : d.data.title,
10438 description : d.data.description,
10439 venue : d.data.venue
10444 this.renderEvents();
10447 this.maskEl.hide();
10451 onBeforeLoad: function()
10453 this.clearEvents();
10456 this.maskEl.show();
10470 * @class Roo.bootstrap.Popover
10471 * @extends Roo.bootstrap.Component
10472 * Bootstrap Popover class
10473 * @cfg {String} html contents of the popover (or false to use children..)
10474 * @cfg {String} title of popover (or false to hide)
10475 * @cfg {String} placement how it is placed
10476 * @cfg {String} trigger click || hover (or false to trigger manually)
10477 * @cfg {String} over what (parent or false to trigger manually.)
10480 * Create a new Popover
10481 * @param {Object} config The config object
10484 Roo.bootstrap.Popover = function(config){
10485 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
10488 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
10490 title: 'Fill in a title',
10493 placement : 'right',
10494 trigger : 'hover', // hover
10498 can_build_overlaid : false,
10500 getChildContainer : function()
10502 return this.el.select('.popover-content',true).first();
10505 getAutoCreate : function(){
10506 Roo.log('make popover?');
10508 cls : 'popover roo-dynamic',
10509 style: 'display:block',
10515 cls : 'popover-inner',
10519 cls: 'popover-title',
10523 cls : 'popover-content',
10534 setTitle: function(str)
10536 this.el.select('.popover-title',true).first().dom.innerHTML = str;
10538 setContent: function(str)
10540 this.el.select('.popover-content',true).first().dom.innerHTML = str;
10542 // as it get's added to the bottom of the page.
10543 onRender : function(ct, position)
10545 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
10547 var cfg = Roo.apply({}, this.getAutoCreate());
10551 cfg.cls += ' ' + this.cls;
10554 cfg.style = this.style;
10556 Roo.log("adding to ")
10557 this.el = Roo.get(document.body).createChild(cfg, position);
10563 initEvents : function()
10565 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
10566 this.el.enableDisplayMode('block');
10568 if (this.over === false) {
10571 if (this.triggers === false) {
10574 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
10575 var triggers = this.trigger ? this.trigger.split(' ') : [];
10576 Roo.each(triggers, function(trigger) {
10578 if (trigger == 'click') {
10579 on_el.on('click', this.toggle, this);
10580 } else if (trigger != 'manual') {
10581 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
10582 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
10584 on_el.on(eventIn ,this.enter, this);
10585 on_el.on(eventOut, this.leave, this);
10596 toggle : function () {
10597 this.hoverState == 'in' ? this.leave() : this.enter();
10600 enter : function () {
10603 clearTimeout(this.timeout);
10605 this.hoverState = 'in'
10607 if (!this.delay || !this.delay.show) {
10612 this.timeout = setTimeout(function () {
10613 if (_t.hoverState == 'in') {
10616 }, this.delay.show)
10618 leave : function() {
10619 clearTimeout(this.timeout);
10621 this.hoverState = 'out'
10623 if (!this.delay || !this.delay.hide) {
10628 this.timeout = setTimeout(function () {
10629 if (_t.hoverState == 'out') {
10632 }, this.delay.hide)
10635 show : function (on_el)
10638 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
10641 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
10642 if (this.html !== false) {
10643 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
10645 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
10646 if (!this.title.length) {
10647 this.el.select('.popover-title',true).hide();
10650 var placement = typeof this.placement == 'function' ?
10651 this.placement.call(this, this.el, on_el) :
10654 var autoToken = /\s?auto?\s?/i;
10655 var autoPlace = autoToken.test(placement);
10657 placement = placement.replace(autoToken, '') || 'top';
10661 //this.el.setXY([0,0]);
10663 this.el.dom.style.display='block';
10664 this.el.addClass(placement);
10666 //this.el.appendTo(on_el);
10668 var p = this.getPosition();
10669 var box = this.el.getBox();
10674 var align = Roo.bootstrap.Popover.alignment[placement]
10675 this.el.alignTo(on_el, align[0],align[1]);
10676 //var arrow = this.el.select('.arrow',true).first();
10677 //arrow.set(align[2],
10679 this.el.addClass('in');
10680 this.hoverState = null;
10682 if (this.el.hasClass('fade')) {
10689 this.el.setXY([0,0]);
10690 this.el.removeClass('in');
10697 Roo.bootstrap.Popover.alignment = {
10698 'left' : ['r-l', [-10,0], 'right'],
10699 'right' : ['l-r', [10,0], 'left'],
10700 'bottom' : ['t-b', [0,10], 'top'],
10701 'top' : [ 'b-t', [0,-10], 'bottom']
10712 * @class Roo.bootstrap.Progress
10713 * @extends Roo.bootstrap.Component
10714 * Bootstrap Progress class
10715 * @cfg {Boolean} striped striped of the progress bar
10716 * @cfg {Boolean} active animated of the progress bar
10720 * Create a new Progress
10721 * @param {Object} config The config object
10724 Roo.bootstrap.Progress = function(config){
10725 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
10728 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
10733 getAutoCreate : function(){
10741 cfg.cls += ' progress-striped';
10745 cfg.cls += ' active';
10764 * @class Roo.bootstrap.ProgressBar
10765 * @extends Roo.bootstrap.Component
10766 * Bootstrap ProgressBar class
10767 * @cfg {Number} aria_valuenow aria-value now
10768 * @cfg {Number} aria_valuemin aria-value min
10769 * @cfg {Number} aria_valuemax aria-value max
10770 * @cfg {String} label label for the progress bar
10771 * @cfg {String} panel (success | info | warning | danger )
10772 * @cfg {String} role role of the progress bar
10773 * @cfg {String} sr_only text
10777 * Create a new ProgressBar
10778 * @param {Object} config The config object
10781 Roo.bootstrap.ProgressBar = function(config){
10782 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
10785 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
10789 aria_valuemax : 100,
10795 getAutoCreate : function()
10800 cls: 'progress-bar',
10801 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
10813 cfg.role = this.role;
10816 if(this.aria_valuenow){
10817 cfg['aria-valuenow'] = this.aria_valuenow;
10820 if(this.aria_valuemin){
10821 cfg['aria-valuemin'] = this.aria_valuemin;
10824 if(this.aria_valuemax){
10825 cfg['aria-valuemax'] = this.aria_valuemax;
10828 if(this.label && !this.sr_only){
10829 cfg.html = this.label;
10833 cfg.cls += ' progress-bar-' + this.panel;
10839 update : function(aria_valuenow)
10841 this.aria_valuenow = aria_valuenow;
10843 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
10858 * @class Roo.bootstrap.TabPanel
10859 * @extends Roo.bootstrap.Component
10860 * Bootstrap TabPanel class
10861 * @cfg {Boolean} active panel active
10862 * @cfg {String} html panel content
10863 * @cfg {String} tabId tab relate id
10867 * Create a new TabPanel
10868 * @param {Object} config The config object
10871 Roo.bootstrap.TabPanel = function(config){
10872 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
10875 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
10881 getAutoCreate : function(){
10885 html: this.html || ''
10889 cfg.cls += ' active';
10893 cfg.tabId = this.tabId;
10911 * @class Roo.bootstrap.DateField
10912 * @extends Roo.bootstrap.Input
10913 * Bootstrap DateField class
10914 * @cfg {Number} weekStart default 0
10915 * @cfg {Number} weekStart default 0
10916 * @cfg {Number} viewMode default empty, (months|years)
10917 * @cfg {Number} minViewMode default empty, (months|years)
10918 * @cfg {Number} startDate default -Infinity
10919 * @cfg {Number} endDate default Infinity
10920 * @cfg {Boolean} todayHighlight default false
10921 * @cfg {Boolean} todayBtn default false
10922 * @cfg {Boolean} calendarWeeks default false
10923 * @cfg {Object} daysOfWeekDisabled default empty
10925 * @cfg {Boolean} keyboardNavigation default true
10926 * @cfg {String} language default en
10929 * Create a new DateField
10930 * @param {Object} config The config object
10933 Roo.bootstrap.DateField = function(config){
10934 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
10938 * Fires when this field show.
10939 * @param {Roo.bootstrap.DateField} this
10940 * @param {Mixed} date The date value
10945 * Fires when this field hide.
10946 * @param {Roo.bootstrap.DateField} this
10947 * @param {Mixed} date The date value
10952 * Fires when select a date.
10953 * @param {Roo.bootstrap.DateField} this
10954 * @param {Mixed} date The date value
10960 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
10963 * @cfg {String} format
10964 * The default date format string which can be overriden for localization support. The format must be
10965 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
10969 * @cfg {String} altFormats
10970 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
10971 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
10973 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
10981 todayHighlight : false,
10987 keyboardNavigation: true,
10989 calendarWeeks: false,
10991 startDate: -Infinity,
10995 daysOfWeekDisabled: [],
10999 UTCDate: function()
11001 return new Date(Date.UTC.apply(Date, arguments));
11004 UTCToday: function()
11006 var today = new Date();
11007 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
11010 getDate: function() {
11011 var d = this.getUTCDate();
11012 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
11015 getUTCDate: function() {
11019 setDate: function(d) {
11020 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
11023 setUTCDate: function(d) {
11025 this.setValue(this.formatDate(this.date));
11028 onRender: function(ct, position)
11031 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
11033 this.language = this.language || 'en';
11034 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
11035 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
11037 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
11038 this.format = this.format || 'm/d/y';
11039 this.isInline = false;
11040 this.isInput = true;
11041 this.component = this.el.select('.add-on', true).first() || false;
11042 this.component = (this.component && this.component.length === 0) ? false : this.component;
11043 this.hasInput = this.component && this.inputEL().length;
11045 if (typeof(this.minViewMode === 'string')) {
11046 switch (this.minViewMode) {
11048 this.minViewMode = 1;
11051 this.minViewMode = 2;
11054 this.minViewMode = 0;
11059 if (typeof(this.viewMode === 'string')) {
11060 switch (this.viewMode) {
11073 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
11075 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
11077 this.picker().on('mousedown', this.onMousedown, this);
11078 this.picker().on('click', this.onClick, this);
11080 this.picker().addClass('datepicker-dropdown');
11082 this.startViewMode = this.viewMode;
11085 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
11086 if(!this.calendarWeeks){
11091 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
11092 v.attr('colspan', function(i, val){
11093 return parseInt(val) + 1;
11098 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
11100 this.setStartDate(this.startDate);
11101 this.setEndDate(this.endDate);
11103 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
11110 if(this.isInline) {
11115 picker : function()
11117 return this.el.select('.datepicker', true).first();
11120 fillDow: function()
11122 var dowCnt = this.weekStart;
11131 if(this.calendarWeeks){
11139 while (dowCnt < this.weekStart + 7) {
11143 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
11147 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
11150 fillMonths: function()
11153 var months = this.picker().select('>.datepicker-months td', true).first();
11155 months.dom.innerHTML = '';
11161 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
11164 months.createChild(month);
11169 update: function(){
11171 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
11173 if (this.date < this.startDate) {
11174 this.viewDate = new Date(this.startDate);
11175 } else if (this.date > this.endDate) {
11176 this.viewDate = new Date(this.endDate);
11178 this.viewDate = new Date(this.date);
11185 var d = new Date(this.viewDate),
11186 year = d.getUTCFullYear(),
11187 month = d.getUTCMonth(),
11188 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
11189 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
11190 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
11191 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
11192 currentDate = this.date && this.date.valueOf(),
11193 today = this.UTCToday();
11195 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
11197 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
11199 // this.picker.select('>tfoot th.today').
11200 // .text(dates[this.language].today)
11201 // .toggle(this.todayBtn !== false);
11203 this.updateNavArrows();
11206 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
11208 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
11210 prevMonth.setUTCDate(day);
11212 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
11214 var nextMonth = new Date(prevMonth);
11216 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
11218 nextMonth = nextMonth.valueOf();
11220 var fillMonths = false;
11222 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
11224 while(prevMonth.valueOf() < nextMonth) {
11227 if (prevMonth.getUTCDay() === this.weekStart) {
11229 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
11237 if(this.calendarWeeks){
11238 // ISO 8601: First week contains first thursday.
11239 // ISO also states week starts on Monday, but we can be more abstract here.
11241 // Start of current week: based on weekstart/current date
11242 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
11243 // Thursday of this week
11244 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
11245 // First Thursday of year, year from thursday
11246 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
11247 // Calendar week: ms between thursdays, div ms per day, div 7 days
11248 calWeek = (th - yth) / 864e5 / 7 + 1;
11250 fillMonths.cn.push({
11258 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
11260 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
11263 if (this.todayHighlight &&
11264 prevMonth.getUTCFullYear() == today.getFullYear() &&
11265 prevMonth.getUTCMonth() == today.getMonth() &&
11266 prevMonth.getUTCDate() == today.getDate()) {
11267 clsName += ' today';
11270 if (currentDate && prevMonth.valueOf() === currentDate) {
11271 clsName += ' active';
11274 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
11275 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
11276 clsName += ' disabled';
11279 fillMonths.cn.push({
11281 cls: 'day ' + clsName,
11282 html: prevMonth.getDate()
11285 prevMonth.setDate(prevMonth.getDate()+1);
11288 var currentYear = this.date && this.date.getUTCFullYear();
11289 var currentMonth = this.date && this.date.getUTCMonth();
11291 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
11293 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
11294 v.removeClass('active');
11296 if(currentYear === year && k === currentMonth){
11297 v.addClass('active');
11300 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
11301 v.addClass('disabled');
11307 year = parseInt(year/10, 10) * 10;
11309 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
11311 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
11314 for (var i = -1; i < 11; i++) {
11315 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
11317 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
11325 showMode: function(dir) {
11327 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
11329 Roo.each(this.picker().select('>div',true).elements, function(v){
11330 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
11333 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
11338 if(this.isInline) return;
11340 this.picker().removeClass(['bottom', 'top']);
11342 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
11344 * place to the top of element!
11348 this.picker().addClass('top');
11349 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
11354 this.picker().addClass('bottom');
11356 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
11359 parseDate : function(value){
11360 if(!value || value instanceof Date){
11363 var v = Date.parseDate(value, this.format);
11364 if (!v && this.useIso) {
11365 v = Date.parseDate(value, 'Y-m-d');
11367 if(!v && this.altFormats){
11368 if(!this.altFormatsArray){
11369 this.altFormatsArray = this.altFormats.split("|");
11371 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
11372 v = Date.parseDate(value, this.altFormatsArray[i]);
11378 formatDate : function(date, fmt){
11379 return (!date || !(date instanceof Date)) ?
11380 date : date.dateFormat(fmt || this.format);
11383 onFocus : function()
11385 Roo.bootstrap.DateField.superclass.onFocus.call(this);
11389 onBlur : function()
11391 Roo.bootstrap.DateField.superclass.onBlur.call(this);
11397 this.picker().show();
11401 this.fireEvent('show', this, this.date);
11406 if(this.isInline) return;
11407 this.picker().hide();
11408 this.viewMode = this.startViewMode;
11411 this.fireEvent('hide', this, this.date);
11415 onMousedown: function(e){
11416 e.stopPropagation();
11417 e.preventDefault();
11420 keyup: function(e){
11421 Roo.bootstrap.DateField.superclass.keyup.call(this);
11426 setValue: function(v){
11427 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
11429 this.fireEvent('select', this, this.date);
11433 fireKey: function(e){
11434 if (!this.picker().isVisible()){
11435 if (e.keyCode == 27) // allow escape to hide and re-show picker
11439 var dateChanged = false,
11441 newDate, newViewDate;
11445 e.preventDefault();
11449 if (!this.keyboardNavigation) break;
11450 dir = e.keyCode == 37 ? -1 : 1;
11453 newDate = this.moveYear(this.date, dir);
11454 newViewDate = this.moveYear(this.viewDate, dir);
11455 } else if (e.shiftKey){
11456 newDate = this.moveMonth(this.date, dir);
11457 newViewDate = this.moveMonth(this.viewDate, dir);
11459 newDate = new Date(this.date);
11460 newDate.setUTCDate(this.date.getUTCDate() + dir);
11461 newViewDate = new Date(this.viewDate);
11462 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
11464 if (this.dateWithinRange(newDate)){
11465 this.date = newDate;
11466 this.viewDate = newViewDate;
11467 this.setValue(this.formatDate(this.date));
11469 e.preventDefault();
11470 dateChanged = true;
11475 if (!this.keyboardNavigation) break;
11476 dir = e.keyCode == 38 ? -1 : 1;
11478 newDate = this.moveYear(this.date, dir);
11479 newViewDate = this.moveYear(this.viewDate, dir);
11480 } else if (e.shiftKey){
11481 newDate = this.moveMonth(this.date, dir);
11482 newViewDate = this.moveMonth(this.viewDate, dir);
11484 newDate = new Date(this.date);
11485 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
11486 newViewDate = new Date(this.viewDate);
11487 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
11489 if (this.dateWithinRange(newDate)){
11490 this.date = newDate;
11491 this.viewDate = newViewDate;
11492 this.setValue(this.formatDate(this.date));
11494 e.preventDefault();
11495 dateChanged = true;
11499 this.setValue(this.formatDate(this.date));
11501 e.preventDefault();
11504 this.setValue(this.formatDate(this.date));
11511 onClick: function(e) {
11512 e.stopPropagation();
11513 e.preventDefault();
11515 var target = e.getTarget();
11517 if(target.nodeName.toLowerCase() === 'i'){
11518 target = Roo.get(target).dom.parentNode;
11521 var nodeName = target.nodeName;
11522 var className = target.className;
11523 var html = target.innerHTML;
11525 switch(nodeName.toLowerCase()) {
11527 switch(className) {
11533 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
11534 switch(this.viewMode){
11536 this.viewDate = this.moveMonth(this.viewDate, dir);
11540 this.viewDate = this.moveYear(this.viewDate, dir);
11546 var date = new Date();
11547 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
11549 this.setValue(this.formatDate(this.date));
11555 if (className.indexOf('disabled') === -1) {
11556 this.viewDate.setUTCDate(1);
11557 if (className.indexOf('month') !== -1) {
11558 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
11560 var year = parseInt(html, 10) || 0;
11561 this.viewDate.setUTCFullYear(year);
11570 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
11571 var day = parseInt(html, 10) || 1;
11572 var year = this.viewDate.getUTCFullYear(),
11573 month = this.viewDate.getUTCMonth();
11575 if (className.indexOf('old') !== -1) {
11582 } else if (className.indexOf('new') !== -1) {
11590 this.date = this.UTCDate(year, month, day,0,0,0,0);
11591 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
11593 this.setValue(this.formatDate(this.date));
11600 setStartDate: function(startDate){
11601 this.startDate = startDate || -Infinity;
11602 if (this.startDate !== -Infinity) {
11603 this.startDate = this.parseDate(this.startDate);
11606 this.updateNavArrows();
11609 setEndDate: function(endDate){
11610 this.endDate = endDate || Infinity;
11611 if (this.endDate !== Infinity) {
11612 this.endDate = this.parseDate(this.endDate);
11615 this.updateNavArrows();
11618 setDaysOfWeekDisabled: function(daysOfWeekDisabled){
11619 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
11620 if (typeof(this.daysOfWeekDisabled) !== 'object') {
11621 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
11623 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
11624 return parseInt(d, 10);
11627 this.updateNavArrows();
11630 updateNavArrows: function() {
11631 var d = new Date(this.viewDate),
11632 year = d.getUTCFullYear(),
11633 month = d.getUTCMonth();
11635 Roo.each(this.picker().select('.prev', true).elements, function(v){
11637 switch (this.viewMode) {
11640 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
11646 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
11653 Roo.each(this.picker().select('.next', true).elements, function(v){
11655 switch (this.viewMode) {
11658 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
11664 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
11672 moveMonth: function(date, dir){
11673 if (!dir) return date;
11674 var new_date = new Date(date.valueOf()),
11675 day = new_date.getUTCDate(),
11676 month = new_date.getUTCMonth(),
11677 mag = Math.abs(dir),
11679 dir = dir > 0 ? 1 : -1;
11682 // If going back one month, make sure month is not current month
11683 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
11685 return new_date.getUTCMonth() == month;
11687 // If going forward one month, make sure month is as expected
11688 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
11690 return new_date.getUTCMonth() != new_month;
11692 new_month = month + dir;
11693 new_date.setUTCMonth(new_month);
11694 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
11695 if (new_month < 0 || new_month > 11)
11696 new_month = (new_month + 12) % 12;
11698 // For magnitudes >1, move one month at a time...
11699 for (var i=0; i<mag; i++)
11700 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
11701 new_date = this.moveMonth(new_date, dir);
11702 // ...then reset the day, keeping it in the new month
11703 new_month = new_date.getUTCMonth();
11704 new_date.setUTCDate(day);
11706 return new_month != new_date.getUTCMonth();
11709 // Common date-resetting loop -- if date is beyond end of month, make it
11712 new_date.setUTCDate(--day);
11713 new_date.setUTCMonth(new_month);
11718 moveYear: function(date, dir){
11719 return this.moveMonth(date, dir*12);
11722 dateWithinRange: function(date){
11723 return date >= this.startDate && date <= this.endDate;
11727 remove: function() {
11728 this.picker().remove();
11733 Roo.apply(Roo.bootstrap.DateField, {
11744 html: '<i class="icon-arrow-left"/>'
11754 html: '<i class="icon-arrow-right"/>'
11796 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
11797 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
11798 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
11799 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
11800 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
11813 navFnc: 'FullYear',
11818 navFnc: 'FullYear',
11823 Roo.apply(Roo.bootstrap.DateField, {
11827 cls: 'datepicker dropdown-menu',
11831 cls: 'datepicker-days',
11835 cls: 'table-condensed',
11837 Roo.bootstrap.DateField.head,
11841 Roo.bootstrap.DateField.footer
11848 cls: 'datepicker-months',
11852 cls: 'table-condensed',
11854 Roo.bootstrap.DateField.head,
11855 Roo.bootstrap.DateField.content,
11856 Roo.bootstrap.DateField.footer
11863 cls: 'datepicker-years',
11867 cls: 'table-condensed',
11869 Roo.bootstrap.DateField.head,
11870 Roo.bootstrap.DateField.content,
11871 Roo.bootstrap.DateField.footer
11890 * @class Roo.bootstrap.TimeField
11891 * @extends Roo.bootstrap.Input
11892 * Bootstrap DateField class
11896 * Create a new TimeField
11897 * @param {Object} config The config object
11900 Roo.bootstrap.TimeField = function(config){
11901 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
11905 * Fires when this field show.
11906 * @param {Roo.bootstrap.DateField} this
11907 * @param {Mixed} date The date value
11912 * Fires when this field hide.
11913 * @param {Roo.bootstrap.DateField} this
11914 * @param {Mixed} date The date value
11919 * Fires when select a date.
11920 * @param {Roo.bootstrap.DateField} this
11921 * @param {Mixed} date The date value
11927 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
11930 * @cfg {String} format
11931 * The default time format string which can be overriden for localization support. The format must be
11932 * valid according to {@link Date#parseDate} (defaults to 'H:i').
11936 onRender: function(ct, position)
11939 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
11941 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
11943 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
11945 this.pop = this.picker().select('>.datepicker-time',true).first();
11946 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
11948 this.picker().on('mousedown', this.onMousedown, this);
11949 this.picker().on('click', this.onClick, this);
11951 this.picker().addClass('datepicker-dropdown');
11956 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
11957 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
11958 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
11959 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
11960 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
11961 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
11965 fireKey: function(e){
11966 if (!this.picker().isVisible()){
11967 if (e.keyCode == 27) // allow escape to hide and re-show picker
11972 e.preventDefault();
11980 this.onTogglePeriod();
11983 this.onIncrementMinutes();
11986 this.onDecrementMinutes();
11995 onClick: function(e) {
11996 e.stopPropagation();
11997 e.preventDefault();
12000 picker : function()
12002 return this.el.select('.datepicker', true).first();
12005 fillTime: function()
12007 var time = this.pop.select('tbody', true).first();
12009 time.dom.innerHTML = '';
12024 cls: 'hours-up glyphicon glyphicon-chevron-up'
12044 cls: 'minutes-up glyphicon glyphicon-chevron-up'
12065 cls: 'timepicker-hour',
12080 cls: 'timepicker-minute',
12095 cls: 'btn btn-primary period',
12117 cls: 'hours-down glyphicon glyphicon-chevron-down'
12137 cls: 'minutes-down glyphicon glyphicon-chevron-down'
12155 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
12162 var hours = this.time.getHours();
12163 var minutes = this.time.getMinutes();
12176 hours = hours - 12;
12180 hours = '0' + hours;
12184 minutes = '0' + minutes;
12187 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
12188 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
12189 this.pop.select('button', true).first().dom.innerHTML = period;
12195 this.picker().removeClass(['bottom', 'top']);
12197 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
12199 * place to the top of element!
12203 this.picker().addClass('top');
12204 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12209 this.picker().addClass('bottom');
12211 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12214 onFocus : function()
12216 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
12220 onBlur : function()
12222 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
12228 this.picker().show();
12233 this.fireEvent('show', this, this.date);
12238 this.picker().hide();
12241 this.fireEvent('hide', this, this.date);
12244 setTime : function()
12247 this.setValue(this.time.format(this.format));
12249 this.fireEvent('select', this, this.date);
12254 onMousedown: function(e){
12255 e.stopPropagation();
12256 e.preventDefault();
12259 onIncrementHours: function()
12261 Roo.log('onIncrementHours');
12262 this.time = this.time.add(Date.HOUR, 1);
12267 onDecrementHours: function()
12269 Roo.log('onDecrementHours');
12270 this.time = this.time.add(Date.HOUR, -1);
12274 onIncrementMinutes: function()
12276 Roo.log('onIncrementMinutes');
12277 this.time = this.time.add(Date.MINUTE, 1);
12281 onDecrementMinutes: function()
12283 Roo.log('onDecrementMinutes');
12284 this.time = this.time.add(Date.MINUTE, -1);
12288 onTogglePeriod: function()
12290 Roo.log('onTogglePeriod');
12291 this.time = this.time.add(Date.HOUR, 12);
12298 Roo.apply(Roo.bootstrap.TimeField, {
12328 cls: 'btn btn-info ok',
12340 Roo.apply(Roo.bootstrap.TimeField, {
12344 cls: 'datepicker dropdown-menu',
12348 cls: 'datepicker-time',
12352 cls: 'table-condensed',
12354 Roo.bootstrap.TimeField.content,
12355 Roo.bootstrap.TimeField.footer
12374 * @class Roo.bootstrap.CheckBox
12375 * @extends Roo.bootstrap.Input
12376 * Bootstrap CheckBox class
12378 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
12379 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
12380 * @cfg {String} boxLabel The text that appears beside the checkbox
12381 * @cfg {Boolean} checked initnal the element
12384 * Create a new CheckBox
12385 * @param {Object} config The config object
12388 Roo.bootstrap.CheckBox = function(config){
12389 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
12394 * Fires when the element is checked or unchecked.
12395 * @param {Roo.bootstrap.CheckBox} this This input
12396 * @param {Boolean} checked The new checked value
12402 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
12404 inputType: 'checkbox',
12410 getAutoCreate : function()
12412 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
12418 cfg.cls = 'form-group' //input-group
12423 type : this.inputType,
12424 value : (!this.checked) ? this.valueOff : this.inputValue,
12426 placeholder : this.placeholder || ''
12430 if (this.disabled) {
12431 input.disabled=true;
12435 input.checked = this.checked;
12439 input.name = this.name;
12443 input.cls += ' input-' + this.size;
12447 ['xs','sm','md','lg'].map(function(size){
12448 if (settings[size]) {
12449 cfg.cls += ' col-' + size + '-' + settings[size];
12453 var inputblock = input;
12455 if (this.before || this.after) {
12458 cls : 'input-group',
12462 inputblock.cn.push({
12464 cls : 'input-group-addon',
12468 inputblock.cn.push(input);
12470 inputblock.cn.push({
12472 cls : 'input-group-addon',
12479 if (align ==='left' && this.fieldLabel.length) {
12480 Roo.log("left and has label");
12486 cls : 'control-label col-md-' + this.labelWidth,
12487 html : this.fieldLabel
12491 cls : "col-md-" + (12 - this.labelWidth),
12498 } else if ( this.fieldLabel.length) {
12503 tag: this.boxLabel ? 'span' : 'label',
12505 cls: 'control-label box-input-label',
12506 //cls : 'input-group-addon',
12507 html : this.fieldLabel
12517 Roo.log(" no label && no align");
12532 html: this.boxLabel
12541 * return the real input element.
12543 inputEl: function ()
12545 return this.el.select('input.form-box',true).first();
12548 initEvents : function()
12550 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
12552 this.inputEl().on('click', this.onClick, this);
12556 onClick : function()
12558 this.setChecked(!this.checked);
12561 setChecked : function(state,suppressEvent)
12563 this.checked = state;
12565 this.inputEl().dom.checked = state;
12567 if(suppressEvent !== true){
12568 this.fireEvent('check', this, state);
12571 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
12575 setValue : function(v,suppressEvent)
12577 Roo.log('run set value on checkbox?!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
12578 Roo.log(this.fieldLabel);
12580 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
12594 * @class Roo.bootstrap.Radio
12595 * @extends Roo.bootstrap.CheckBox
12596 * Bootstrap Radio class
12599 * Create a new Radio
12600 * @param {Object} config The config object
12603 Roo.bootstrap.Radio = function(config){
12604 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
12608 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
12610 inputType: 'radio',
12614 getAutoCreate : function()
12616 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
12622 cfg.cls = 'form-group' //input-group
12627 type : this.inputType,
12628 value : (!this.checked) ? this.valueOff : this.inputValue,
12630 placeholder : this.placeholder || ''
12634 if (this.disabled) {
12635 input.disabled=true;
12639 input.checked = this.checked;
12643 input.name = this.name;
12647 input.cls += ' input-' + this.size;
12651 ['xs','sm','md','lg'].map(function(size){
12652 if (settings[size]) {
12653 cfg.cls += ' col-' + size + '-' + settings[size];
12657 var inputblock = input;
12659 if (this.before || this.after) {
12662 cls : 'input-group',
12666 inputblock.cn.push({
12668 cls : 'input-group-addon',
12672 inputblock.cn.push(input);
12674 inputblock.cn.push({
12676 cls : 'input-group-addon',
12683 if (align ==='left' && this.fieldLabel.length) {
12684 Roo.log("left and has label");
12690 cls : 'control-label col-md-' + this.labelWidth,
12691 html : this.fieldLabel
12695 cls : "col-md-" + (12 - this.labelWidth),
12702 } else if ( this.fieldLabel.length) {
12709 cls: 'control-label box-input-label',
12710 //cls : 'input-group-addon',
12711 html : this.fieldLabel
12721 Roo.log(" no label && no align");
12736 html: this.boxLabel
12744 onClick : function()
12746 this.setChecked(true);
12749 setChecked : function(state,suppressEvent)
12751 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
12752 v.dom.checked = false;
12755 this.checked = state;
12756 this.inputEl().dom.checked = state;
12758 if(suppressEvent !== true){
12759 this.fireEvent('check', this, state);
12762 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
12766 getGroupValue : function()
12769 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
12770 if(v.dom.checked == true){
12771 value = v.dom.value;
12779 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
12780 * @return {Mixed} value The field value
12782 getValue : function(){
12783 return this.getGroupValue();
12789 //<script type="text/javascript">
12792 * Based Ext JS Library 1.1.1
12793 * Copyright(c) 2006-2007, Ext JS, LLC.
12799 * @class Roo.HtmlEditorCore
12800 * @extends Roo.Component
12801 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
12803 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
12806 Roo.HtmlEditorCore = function(config){
12809 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
12812 * @event initialize
12813 * Fires when the editor is fully initialized (including the iframe)
12814 * @param {Roo.HtmlEditorCore} this
12819 * Fires when the editor is first receives the focus. Any insertion must wait
12820 * until after this event.
12821 * @param {Roo.HtmlEditorCore} this
12825 * @event beforesync
12826 * Fires before the textarea is updated with content from the editor iframe. Return false
12827 * to cancel the sync.
12828 * @param {Roo.HtmlEditorCore} this
12829 * @param {String} html
12833 * @event beforepush
12834 * Fires before the iframe editor is updated with content from the textarea. Return false
12835 * to cancel the push.
12836 * @param {Roo.HtmlEditorCore} this
12837 * @param {String} html
12842 * Fires when the textarea is updated with content from the editor iframe.
12843 * @param {Roo.HtmlEditorCore} this
12844 * @param {String} html
12849 * Fires when the iframe editor is updated with content from the textarea.
12850 * @param {Roo.HtmlEditorCore} this
12851 * @param {String} html
12856 * @event editorevent
12857 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
12858 * @param {Roo.HtmlEditorCore} this
12866 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
12870 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
12876 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
12881 * @cfg {Number} height (in pixels)
12885 * @cfg {Number} width (in pixels)
12890 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
12893 stylesheets: false,
12898 // private properties
12899 validationEvent : false,
12901 initialized : false,
12903 sourceEditMode : false,
12904 onFocus : Roo.emptyFn,
12906 hideMode:'offsets',
12912 * Protected method that will not generally be called directly. It
12913 * is called when the editor initializes the iframe with HTML contents. Override this method if you
12914 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
12916 getDocMarkup : function(){
12919 Roo.log(this.stylesheets);
12921 // inherit styels from page...??
12922 if (this.stylesheets === false) {
12924 Roo.get(document.head).select('style').each(function(node) {
12925 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
12928 Roo.get(document.head).select('link').each(function(node) {
12929 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
12932 } else if (!this.stylesheets.length) {
12934 st = '<style type="text/css">' +
12935 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
12938 Roo.each(this.stylesheets, function(s) {
12939 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
12944 st += '<style type="text/css">' +
12945 'IMG { cursor: pointer } ' +
12949 return '<html><head>' + st +
12950 //<style type="text/css">' +
12951 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
12953 ' </head><body class="roo-htmleditor-body"></body></html>';
12957 onRender : function(ct, position)
12960 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
12961 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
12964 this.el.dom.style.border = '0 none';
12965 this.el.dom.setAttribute('tabIndex', -1);
12966 this.el.addClass('x-hidden hide');
12970 if(Roo.isIE){ // fix IE 1px bogus margin
12971 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
12975 this.frameId = Roo.id();
12979 var iframe = this.owner.wrap.createChild({
12981 cls: 'form-control', // bootstrap..
12983 name: this.frameId,
12984 frameBorder : 'no',
12985 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
12990 this.iframe = iframe.dom;
12992 this.assignDocWin();
12994 this.doc.designMode = 'on';
12997 this.doc.write(this.getDocMarkup());
13001 var task = { // must defer to wait for browser to be ready
13003 //console.log("run task?" + this.doc.readyState);
13004 this.assignDocWin();
13005 if(this.doc.body || this.doc.readyState == 'complete'){
13007 this.doc.designMode="on";
13011 Roo.TaskMgr.stop(task);
13012 this.initEditor.defer(10, this);
13019 Roo.TaskMgr.start(task);
13026 onResize : function(w, h)
13028 Roo.log('resize: ' +w + ',' + h );
13029 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
13033 if(typeof w == 'number'){
13035 this.iframe.style.width = w + 'px';
13037 if(typeof h == 'number'){
13039 this.iframe.style.height = h + 'px';
13041 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
13048 * Toggles the editor between standard and source edit mode.
13049 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
13051 toggleSourceEdit : function(sourceEditMode){
13053 this.sourceEditMode = sourceEditMode === true;
13055 if(this.sourceEditMode){
13057 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
13060 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
13061 //this.iframe.className = '';
13064 //this.setSize(this.owner.wrap.getSize());
13065 //this.fireEvent('editmodechange', this, this.sourceEditMode);
13072 * Protected method that will not generally be called directly. If you need/want
13073 * custom HTML cleanup, this is the method you should override.
13074 * @param {String} html The HTML to be cleaned
13075 * return {String} The cleaned HTML
13077 cleanHtml : function(html){
13078 html = String(html);
13079 if(html.length > 5){
13080 if(Roo.isSafari){ // strip safari nonsense
13081 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
13084 if(html == ' '){
13091 * HTML Editor -> Textarea
13092 * Protected method that will not generally be called directly. Syncs the contents
13093 * of the editor iframe with the textarea.
13095 syncValue : function(){
13096 if(this.initialized){
13097 var bd = (this.doc.body || this.doc.documentElement);
13098 //this.cleanUpPaste(); -- this is done else where and causes havoc..
13099 var html = bd.innerHTML;
13101 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
13102 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
13104 html = '<div style="'+m[0]+'">' + html + '</div>';
13107 html = this.cleanHtml(html);
13108 // fix up the special chars.. normaly like back quotes in word...
13109 // however we do not want to do this with chinese..
13110 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
13111 var cc = b.charCodeAt();
13113 (cc >= 0x4E00 && cc < 0xA000 ) ||
13114 (cc >= 0x3400 && cc < 0x4E00 ) ||
13115 (cc >= 0xf900 && cc < 0xfb00 )
13121 if(this.owner.fireEvent('beforesync', this, html) !== false){
13122 this.el.dom.value = html;
13123 this.owner.fireEvent('sync', this, html);
13129 * Protected method that will not generally be called directly. Pushes the value of the textarea
13130 * into the iframe editor.
13132 pushValue : function(){
13133 if(this.initialized){
13134 var v = this.el.dom.value.trim();
13136 // if(v.length < 1){
13140 if(this.owner.fireEvent('beforepush', this, v) !== false){
13141 var d = (this.doc.body || this.doc.documentElement);
13143 this.cleanUpPaste();
13144 this.el.dom.value = d.innerHTML;
13145 this.owner.fireEvent('push', this, v);
13151 deferFocus : function(){
13152 this.focus.defer(10, this);
13156 focus : function(){
13157 if(this.win && !this.sourceEditMode){
13164 assignDocWin: function()
13166 var iframe = this.iframe;
13169 this.doc = iframe.contentWindow.document;
13170 this.win = iframe.contentWindow;
13172 if (!Roo.get(this.frameId)) {
13175 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
13176 this.win = Roo.get(this.frameId).dom.contentWindow;
13181 initEditor : function(){
13182 //console.log("INIT EDITOR");
13183 this.assignDocWin();
13187 this.doc.designMode="on";
13189 this.doc.write(this.getDocMarkup());
13192 var dbody = (this.doc.body || this.doc.documentElement);
13193 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
13194 // this copies styles from the containing element into thsi one..
13195 // not sure why we need all of this..
13196 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
13197 ss['background-attachment'] = 'fixed'; // w3c
13198 dbody.bgProperties = 'fixed'; // ie
13199 Roo.DomHelper.applyStyles(dbody, ss);
13200 Roo.EventManager.on(this.doc, {
13201 //'mousedown': this.onEditorEvent,
13202 'mouseup': this.onEditorEvent,
13203 'dblclick': this.onEditorEvent,
13204 'click': this.onEditorEvent,
13205 'keyup': this.onEditorEvent,
13210 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
13212 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
13213 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
13215 this.initialized = true;
13217 this.owner.fireEvent('initialize', this);
13222 onDestroy : function(){
13228 //for (var i =0; i < this.toolbars.length;i++) {
13229 // // fixme - ask toolbars for heights?
13230 // this.toolbars[i].onDestroy();
13233 //this.wrap.dom.innerHTML = '';
13234 //this.wrap.remove();
13239 onFirstFocus : function(){
13241 this.assignDocWin();
13244 this.activated = true;
13247 if(Roo.isGecko){ // prevent silly gecko errors
13249 var s = this.win.getSelection();
13250 if(!s.focusNode || s.focusNode.nodeType != 3){
13251 var r = s.getRangeAt(0);
13252 r.selectNodeContents((this.doc.body || this.doc.documentElement));
13257 this.execCmd('useCSS', true);
13258 this.execCmd('styleWithCSS', false);
13261 this.owner.fireEvent('activate', this);
13265 adjustFont: function(btn){
13266 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
13267 //if(Roo.isSafari){ // safari
13270 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
13271 if(Roo.isSafari){ // safari
13272 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
13273 v = (v < 10) ? 10 : v;
13274 v = (v > 48) ? 48 : v;
13275 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
13280 v = Math.max(1, v+adjust);
13282 this.execCmd('FontSize', v );
13285 onEditorEvent : function(e){
13286 this.owner.fireEvent('editorevent', this, e);
13287 // this.updateToolbar();
13288 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
13291 insertTag : function(tg)
13293 // could be a bit smarter... -> wrap the current selected tRoo..
13294 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
13296 range = this.createRange(this.getSelection());
13297 var wrappingNode = this.doc.createElement(tg.toLowerCase());
13298 wrappingNode.appendChild(range.extractContents());
13299 range.insertNode(wrappingNode);
13306 this.execCmd("formatblock", tg);
13310 insertText : function(txt)
13314 var range = this.createRange();
13315 range.deleteContents();
13316 //alert(Sender.getAttribute('label'));
13318 range.insertNode(this.doc.createTextNode(txt));
13324 * Executes a Midas editor command on the editor document and performs necessary focus and
13325 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
13326 * @param {String} cmd The Midas command
13327 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
13329 relayCmd : function(cmd, value){
13331 this.execCmd(cmd, value);
13332 this.owner.fireEvent('editorevent', this);
13333 //this.updateToolbar();
13334 this.owner.deferFocus();
13338 * Executes a Midas editor command directly on the editor document.
13339 * For visual commands, you should use {@link #relayCmd} instead.
13340 * <b>This should only be called after the editor is initialized.</b>
13341 * @param {String} cmd The Midas command
13342 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
13344 execCmd : function(cmd, value){
13345 this.doc.execCommand(cmd, false, value === undefined ? null : value);
13352 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
13354 * @param {String} text | dom node..
13356 insertAtCursor : function(text)
13361 if(!this.activated){
13367 var r = this.doc.selection.createRange();
13378 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
13382 // from jquery ui (MIT licenced)
13384 var win = this.win;
13386 if (win.getSelection && win.getSelection().getRangeAt) {
13387 range = win.getSelection().getRangeAt(0);
13388 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
13389 range.insertNode(node);
13390 } else if (win.document.selection && win.document.selection.createRange) {
13391 // no firefox support
13392 var txt = typeof(text) == 'string' ? text : text.outerHTML;
13393 win.document.selection.createRange().pasteHTML(txt);
13395 // no firefox support
13396 var txt = typeof(text) == 'string' ? text : text.outerHTML;
13397 this.execCmd('InsertHTML', txt);
13406 mozKeyPress : function(e){
13408 var c = e.getCharCode(), cmd;
13411 c = String.fromCharCode(c).toLowerCase();
13425 this.cleanUpPaste.defer(100, this);
13433 e.preventDefault();
13441 fixKeys : function(){ // load time branching for fastest keydown performance
13443 return function(e){
13444 var k = e.getKey(), r;
13447 r = this.doc.selection.createRange();
13450 r.pasteHTML('    ');
13457 r = this.doc.selection.createRange();
13459 var target = r.parentElement();
13460 if(!target || target.tagName.toLowerCase() != 'li'){
13462 r.pasteHTML('<br />');
13468 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
13469 this.cleanUpPaste.defer(100, this);
13475 }else if(Roo.isOpera){
13476 return function(e){
13477 var k = e.getKey();
13481 this.execCmd('InsertHTML','    ');
13484 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
13485 this.cleanUpPaste.defer(100, this);
13490 }else if(Roo.isSafari){
13491 return function(e){
13492 var k = e.getKey();
13496 this.execCmd('InsertText','\t');
13500 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
13501 this.cleanUpPaste.defer(100, this);
13509 getAllAncestors: function()
13511 var p = this.getSelectedNode();
13514 a.push(p); // push blank onto stack..
13515 p = this.getParentElement();
13519 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
13523 a.push(this.doc.body);
13527 lastSelNode : false,
13530 getSelection : function()
13532 this.assignDocWin();
13533 return Roo.isIE ? this.doc.selection : this.win.getSelection();
13536 getSelectedNode: function()
13538 // this may only work on Gecko!!!
13540 // should we cache this!!!!
13545 var range = this.createRange(this.getSelection()).cloneRange();
13548 var parent = range.parentElement();
13550 var testRange = range.duplicate();
13551 testRange.moveToElementText(parent);
13552 if (testRange.inRange(range)) {
13555 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
13558 parent = parent.parentElement;
13563 // is ancestor a text element.
13564 var ac = range.commonAncestorContainer;
13565 if (ac.nodeType == 3) {
13566 ac = ac.parentNode;
13569 var ar = ac.childNodes;
13572 var other_nodes = [];
13573 var has_other_nodes = false;
13574 for (var i=0;i<ar.length;i++) {
13575 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
13578 // fullly contained node.
13580 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
13585 // probably selected..
13586 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
13587 other_nodes.push(ar[i]);
13591 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
13596 has_other_nodes = true;
13598 if (!nodes.length && other_nodes.length) {
13599 nodes= other_nodes;
13601 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
13607 createRange: function(sel)
13609 // this has strange effects when using with
13610 // top toolbar - not sure if it's a great idea.
13611 //this.editor.contentWindow.focus();
13612 if (typeof sel != "undefined") {
13614 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
13616 return this.doc.createRange();
13619 return this.doc.createRange();
13622 getParentElement: function()
13625 this.assignDocWin();
13626 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
13628 var range = this.createRange(sel);
13631 var p = range.commonAncestorContainer;
13632 while (p.nodeType == 3) { // text node
13643 * Range intersection.. the hard stuff...
13647 * [ -- selected range --- ]
13651 * if end is before start or hits it. fail.
13652 * if start is after end or hits it fail.
13654 * if either hits (but other is outside. - then it's not
13660 // @see http://www.thismuchiknow.co.uk/?p=64.
13661 rangeIntersectsNode : function(range, node)
13663 var nodeRange = node.ownerDocument.createRange();
13665 nodeRange.selectNode(node);
13667 nodeRange.selectNodeContents(node);
13670 var rangeStartRange = range.cloneRange();
13671 rangeStartRange.collapse(true);
13673 var rangeEndRange = range.cloneRange();
13674 rangeEndRange.collapse(false);
13676 var nodeStartRange = nodeRange.cloneRange();
13677 nodeStartRange.collapse(true);
13679 var nodeEndRange = nodeRange.cloneRange();
13680 nodeEndRange.collapse(false);
13682 return rangeStartRange.compareBoundaryPoints(
13683 Range.START_TO_START, nodeEndRange) == -1 &&
13684 rangeEndRange.compareBoundaryPoints(
13685 Range.START_TO_START, nodeStartRange) == 1;
13689 rangeCompareNode : function(range, node)
13691 var nodeRange = node.ownerDocument.createRange();
13693 nodeRange.selectNode(node);
13695 nodeRange.selectNodeContents(node);
13699 range.collapse(true);
13701 nodeRange.collapse(true);
13703 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
13704 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
13706 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
13708 var nodeIsBefore = ss == 1;
13709 var nodeIsAfter = ee == -1;
13711 if (nodeIsBefore && nodeIsAfter)
13713 if (!nodeIsBefore && nodeIsAfter)
13714 return 1; //right trailed.
13716 if (nodeIsBefore && !nodeIsAfter)
13717 return 2; // left trailed.
13722 // private? - in a new class?
13723 cleanUpPaste : function()
13725 // cleans up the whole document..
13726 Roo.log('cleanuppaste');
13727 this.cleanUpChildren(this.doc.body);
13728 var clean = this.cleanWordChars(this.doc.body.innerHTML);
13729 if (clean != this.doc.body.innerHTML) {
13730 this.doc.body.innerHTML = clean;
13735 cleanWordChars : function(input) {// change the chars to hex code
13736 var he = Roo.HtmlEditorCore;
13738 var output = input;
13739 Roo.each(he.swapCodes, function(sw) {
13740 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
13742 output = output.replace(swapper, sw[1]);
13749 cleanUpChildren : function (n)
13751 if (!n.childNodes.length) {
13754 for (var i = n.childNodes.length-1; i > -1 ; i--) {
13755 this.cleanUpChild(n.childNodes[i]);
13762 cleanUpChild : function (node)
13765 //console.log(node);
13766 if (node.nodeName == "#text") {
13767 // clean up silly Windows -- stuff?
13770 if (node.nodeName == "#comment") {
13771 node.parentNode.removeChild(node);
13772 // clean up silly Windows -- stuff?
13776 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1) {
13778 node.parentNode.removeChild(node);
13783 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
13785 // remove <a name=....> as rendering on yahoo mailer is borked with this.
13786 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
13788 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
13789 // remove_keep_children = true;
13792 if (remove_keep_children) {
13793 this.cleanUpChildren(node);
13794 // inserts everything just before this node...
13795 while (node.childNodes.length) {
13796 var cn = node.childNodes[0];
13797 node.removeChild(cn);
13798 node.parentNode.insertBefore(cn, node);
13800 node.parentNode.removeChild(node);
13804 if (!node.attributes || !node.attributes.length) {
13805 this.cleanUpChildren(node);
13809 function cleanAttr(n,v)
13812 if (v.match(/^\./) || v.match(/^\//)) {
13815 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
13818 if (v.match(/^#/)) {
13821 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
13822 node.removeAttribute(n);
13826 function cleanStyle(n,v)
13828 if (v.match(/expression/)) { //XSS?? should we even bother..
13829 node.removeAttribute(n);
13832 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
13833 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
13836 var parts = v.split(/;/);
13839 Roo.each(parts, function(p) {
13840 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
13844 var l = p.split(':').shift().replace(/\s+/g,'');
13845 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
13848 if ( cblack.indexOf(l) > -1) {
13849 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
13850 //node.removeAttribute(n);
13854 // only allow 'c whitelisted system attributes'
13855 if ( cwhite.length && cwhite.indexOf(l) < 0) {
13856 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
13857 //node.removeAttribute(n);
13867 if (clean.length) {
13868 node.setAttribute(n, clean.join(';'));
13870 node.removeAttribute(n);
13876 for (var i = node.attributes.length-1; i > -1 ; i--) {
13877 var a = node.attributes[i];
13880 if (a.name.toLowerCase().substr(0,2)=='on') {
13881 node.removeAttribute(a.name);
13884 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
13885 node.removeAttribute(a.name);
13888 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
13889 cleanAttr(a.name,a.value); // fixme..
13892 if (a.name == 'style') {
13893 cleanStyle(a.name,a.value);
13896 /// clean up MS crap..
13897 // tecnically this should be a list of valid class'es..
13900 if (a.name == 'class') {
13901 if (a.value.match(/^Mso/)) {
13902 node.className = '';
13905 if (a.value.match(/body/)) {
13906 node.className = '';
13917 this.cleanUpChildren(node);
13923 // hide stuff that is not compatible
13937 * @event specialkey
13941 * @cfg {String} fieldClass @hide
13944 * @cfg {String} focusClass @hide
13947 * @cfg {String} autoCreate @hide
13950 * @cfg {String} inputType @hide
13953 * @cfg {String} invalidClass @hide
13956 * @cfg {String} invalidText @hide
13959 * @cfg {String} msgFx @hide
13962 * @cfg {String} validateOnBlur @hide
13966 Roo.HtmlEditorCore.white = [
13967 'area', 'br', 'img', 'input', 'hr', 'wbr',
13969 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
13970 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
13971 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
13972 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
13973 'table', 'ul', 'xmp',
13975 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
13978 'dir', 'menu', 'ol', 'ul', 'dl',
13984 Roo.HtmlEditorCore.black = [
13985 // 'embed', 'object', // enable - backend responsiblity to clean thiese
13987 'base', 'basefont', 'bgsound', 'blink', 'body',
13988 'frame', 'frameset', 'head', 'html', 'ilayer',
13989 'iframe', 'layer', 'link', 'meta', 'object',
13990 'script', 'style' ,'title', 'xml' // clean later..
13992 Roo.HtmlEditorCore.clean = [
13993 'script', 'style', 'title', 'xml'
13995 Roo.HtmlEditorCore.remove = [
14000 Roo.HtmlEditorCore.ablack = [
14004 Roo.HtmlEditorCore.aclean = [
14005 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
14009 Roo.HtmlEditorCore.pwhite= [
14010 'http', 'https', 'mailto'
14013 // white listed style attributes.
14014 Roo.HtmlEditorCore.cwhite= [
14015 // 'text-align', /// default is to allow most things..
14021 // black listed style attributes.
14022 Roo.HtmlEditorCore.cblack= [
14023 // 'font-size' -- this can be set by the project
14027 Roo.HtmlEditorCore.swapCodes =[
14046 * @class Roo.bootstrap.HtmlEditor
14047 * @extends Roo.bootstrap.TextArea
14048 * Bootstrap HtmlEditor class
14051 * Create a new HtmlEditor
14052 * @param {Object} config The config object
14055 Roo.bootstrap.HtmlEditor = function(config){
14056 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
14057 if (!this.toolbars) {
14058 this.toolbars = [];
14060 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
14063 * @event initialize
14064 * Fires when the editor is fully initialized (including the iframe)
14065 * @param {HtmlEditor} this
14070 * Fires when the editor is first receives the focus. Any insertion must wait
14071 * until after this event.
14072 * @param {HtmlEditor} this
14076 * @event beforesync
14077 * Fires before the textarea is updated with content from the editor iframe. Return false
14078 * to cancel the sync.
14079 * @param {HtmlEditor} this
14080 * @param {String} html
14084 * @event beforepush
14085 * Fires before the iframe editor is updated with content from the textarea. Return false
14086 * to cancel the push.
14087 * @param {HtmlEditor} this
14088 * @param {String} html
14093 * Fires when the textarea is updated with content from the editor iframe.
14094 * @param {HtmlEditor} this
14095 * @param {String} html
14100 * Fires when the iframe editor is updated with content from the textarea.
14101 * @param {HtmlEditor} this
14102 * @param {String} html
14106 * @event editmodechange
14107 * Fires when the editor switches edit modes
14108 * @param {HtmlEditor} this
14109 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
14111 editmodechange: true,
14113 * @event editorevent
14114 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
14115 * @param {HtmlEditor} this
14119 * @event firstfocus
14120 * Fires when on first focus - needed by toolbars..
14121 * @param {HtmlEditor} this
14126 * Auto save the htmlEditor value as a file into Events
14127 * @param {HtmlEditor} this
14131 * @event savedpreview
14132 * preview the saved version of htmlEditor
14133 * @param {HtmlEditor} this
14140 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
14144 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
14149 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
14154 * @cfg {Number} height (in pixels)
14158 * @cfg {Number} width (in pixels)
14163 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
14166 stylesheets: false,
14171 // private properties
14172 validationEvent : false,
14174 initialized : false,
14177 onFocus : Roo.emptyFn,
14179 hideMode:'offsets',
14182 tbContainer : false,
14184 toolbarContainer :function() {
14185 return this.wrap.select('.x-html-editor-tb',true).first();
14189 * Protected method that will not generally be called directly. It
14190 * is called when the editor creates its toolbar. Override this method if you need to
14191 * add custom toolbar buttons.
14192 * @param {HtmlEditor} editor
14194 createToolbar : function(){
14196 Roo.log("create toolbars");
14198 this.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard({editor: this} ) ];
14199 this.toolbars[0].render(this.toolbarContainer());
14203 // if (!editor.toolbars || !editor.toolbars.length) {
14204 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
14207 // for (var i =0 ; i < editor.toolbars.length;i++) {
14208 // editor.toolbars[i] = Roo.factory(
14209 // typeof(editor.toolbars[i]) == 'string' ?
14210 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
14211 // Roo.bootstrap.HtmlEditor);
14212 // editor.toolbars[i].init(editor);
14218 onRender : function(ct, position)
14220 // Roo.log("Call onRender: " + this.xtype);
14222 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
14224 this.wrap = this.inputEl().wrap({
14225 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
14228 this.editorcore.onRender(ct, position);
14230 if (this.resizable) {
14231 this.resizeEl = new Roo.Resizable(this.wrap, {
14235 minHeight : this.height,
14236 height: this.height,
14237 handles : this.resizable,
14240 resize : function(r, w, h) {
14241 _t.onResize(w,h); // -something
14247 this.createToolbar(this);
14250 if(!this.width && this.resizable){
14251 this.setSize(this.wrap.getSize());
14253 if (this.resizeEl) {
14254 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
14255 // should trigger onReize..
14261 onResize : function(w, h)
14263 Roo.log('resize: ' +w + ',' + h );
14264 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
14268 if(this.inputEl() ){
14269 if(typeof w == 'number'){
14270 var aw = w - this.wrap.getFrameWidth('lr');
14271 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
14274 if(typeof h == 'number'){
14275 var tbh = -11; // fixme it needs to tool bar size!
14276 for (var i =0; i < this.toolbars.length;i++) {
14277 // fixme - ask toolbars for heights?
14278 tbh += this.toolbars[i].el.getHeight();
14279 //if (this.toolbars[i].footer) {
14280 // tbh += this.toolbars[i].footer.el.getHeight();
14288 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
14289 ah -= 5; // knock a few pixes off for look..
14290 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
14294 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
14295 this.editorcore.onResize(ew,eh);
14300 * Toggles the editor between standard and source edit mode.
14301 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
14303 toggleSourceEdit : function(sourceEditMode)
14305 this.editorcore.toggleSourceEdit(sourceEditMode);
14307 if(this.editorcore.sourceEditMode){
14308 Roo.log('editor - showing textarea');
14311 // Roo.log(this.syncValue());
14313 this.inputEl().removeClass('hide');
14314 this.inputEl().dom.removeAttribute('tabIndex');
14315 this.inputEl().focus();
14317 Roo.log('editor - hiding textarea');
14319 // Roo.log(this.pushValue());
14322 this.inputEl().addClass('hide');
14323 this.inputEl().dom.setAttribute('tabIndex', -1);
14324 //this.deferFocus();
14327 if(this.resizable){
14328 this.setSize(this.wrap.getSize());
14331 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
14334 // private (for BoxComponent)
14335 adjustSize : Roo.BoxComponent.prototype.adjustSize,
14337 // private (for BoxComponent)
14338 getResizeEl : function(){
14342 // private (for BoxComponent)
14343 getPositionEl : function(){
14348 initEvents : function(){
14349 this.originalValue = this.getValue();
14353 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
14356 // markInvalid : Roo.emptyFn,
14358 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
14361 // clearInvalid : Roo.emptyFn,
14363 setValue : function(v){
14364 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
14365 this.editorcore.pushValue();
14370 deferFocus : function(){
14371 this.focus.defer(10, this);
14375 focus : function(){
14376 this.editorcore.focus();
14382 onDestroy : function(){
14388 for (var i =0; i < this.toolbars.length;i++) {
14389 // fixme - ask toolbars for heights?
14390 this.toolbars[i].onDestroy();
14393 this.wrap.dom.innerHTML = '';
14394 this.wrap.remove();
14399 onFirstFocus : function(){
14400 //Roo.log("onFirstFocus");
14401 this.editorcore.onFirstFocus();
14402 for (var i =0; i < this.toolbars.length;i++) {
14403 this.toolbars[i].onFirstFocus();
14409 syncValue : function()
14411 this.editorcore.syncValue();
14414 pushValue : function()
14416 this.editorcore.pushValue();
14420 // hide stuff that is not compatible
14434 * @event specialkey
14438 * @cfg {String} fieldClass @hide
14441 * @cfg {String} focusClass @hide
14444 * @cfg {String} autoCreate @hide
14447 * @cfg {String} inputType @hide
14450 * @cfg {String} invalidClass @hide
14453 * @cfg {String} invalidText @hide
14456 * @cfg {String} msgFx @hide
14459 * @cfg {String} validateOnBlur @hide
14470 * @class Roo.bootstrap.HtmlEditorToolbar1
14475 new Roo.bootstrap.HtmlEditor({
14478 new Roo.bootstrap.HtmlEditorToolbar1({
14479 disable : { fonts: 1 , format: 1, ..., ... , ...],
14485 * @cfg {Object} disable List of elements to disable..
14486 * @cfg {Array} btns List of additional buttons.
14490 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
14493 Roo.bootstrap.HtmlEditor.ToolbarStandard = function(config)
14496 Roo.apply(this, config);
14498 // default disabled, based on 'good practice'..
14499 this.disable = this.disable || {};
14500 Roo.applyIf(this.disable, {
14503 specialElements : true
14505 Roo.bootstrap.HtmlEditor.ToolbarStandard.superclass.constructor.call(this, config);
14507 this.editor = config.editor;
14508 this.editorcore = config.editor.editorcore;
14510 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
14512 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
14513 // dont call parent... till later.
14515 Roo.extend(Roo.bootstrap.HtmlEditor.ToolbarStandard, Roo.bootstrap.Navbar, {
14521 editorcore : false,
14526 "h1","h2","h3","h4","h5","h6",
14528 "abbr", "acronym", "address", "cite", "samp", "var",
14532 onRender : function(ct, position)
14534 // Roo.log("Call onRender: " + this.xtype);
14536 Roo.bootstrap.HtmlEditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
14538 this.el.dom.style.marginBottom = '0';
14540 var editorcore = this.editorcore;
14541 var editor= this.editor;
14544 var btn = function(id,cmd , toggle, handler){
14546 var event = toggle ? 'toggle' : 'click';
14551 xns: Roo.bootstrap,
14554 enableToggle:toggle !== false,
14556 pressed : toggle ? false : null,
14559 a.listeners[toggle ? 'toggle' : 'click'] = function() {
14560 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
14569 xns: Roo.bootstrap,
14570 glyphicon : 'font',
14574 xns: Roo.bootstrap,
14578 Roo.each(this.formats, function(f) {
14579 style.menu.items.push({
14581 xns: Roo.bootstrap,
14582 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
14587 editorcore.insertTag(this.tagname);
14594 children.push(style);
14597 btn('bold',false,true);
14598 btn('italic',false,true);
14599 btn('align-left', 'justifyleft',true);
14600 btn('align-center', 'justifycenter',true);
14601 btn('align-right' , 'justifyright',true);
14602 btn('link', false, false, function(btn) {
14603 //Roo.log("create link?");
14604 var url = prompt(this.createLinkText, this.defaultLinkValue);
14605 if(url && url != 'http:/'+'/'){
14606 this.editorcore.relayCmd('createlink', url);
14609 btn('list','insertunorderedlist',true);
14610 btn('pencil', false,true, function(btn){
14613 this.toggleSourceEdit(btn.pressed);
14619 xns: Roo.bootstrap,
14624 xns: Roo.bootstrap,
14629 cog.menu.items.push({
14631 xns: Roo.bootstrap,
14632 html : Clean styles,
14637 editorcore.insertTag(this.tagname);
14646 this.xtype = 'Navbar';
14648 for(var i=0;i< children.length;i++) {
14650 this.buttons.add(this.addxtypeChild(children[i]));
14654 editor.on('editorevent', this.updateToolbar, this);
14656 onBtnClick : function(id)
14658 this.editorcore.relayCmd(id);
14659 this.editorcore.focus();
14663 * Protected method that will not generally be called directly. It triggers
14664 * a toolbar update by reading the markup state of the current selection in the editor.
14666 updateToolbar: function(){
14668 if(!this.editorcore.activated){
14669 this.editor.onFirstFocus(); // is this neeed?
14673 var btns = this.buttons;
14674 var doc = this.editorcore.doc;
14675 btns.get('bold').setActive(doc.queryCommandState('bold'));
14676 btns.get('italic').setActive(doc.queryCommandState('italic'));
14677 //btns.get('underline').setActive(doc.queryCommandState('underline'));
14679 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
14680 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
14681 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
14683 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
14684 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
14687 var ans = this.editorcore.getAllAncestors();
14688 if (this.formatCombo) {
14691 var store = this.formatCombo.store;
14692 this.formatCombo.setValue("");
14693 for (var i =0; i < ans.length;i++) {
14694 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
14696 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
14704 // hides menus... - so this cant be on a menu...
14705 Roo.bootstrap.MenuMgr.hideAll();
14707 Roo.bootstrap.MenuMgr.hideAll();
14708 //this.editorsyncValue();
14710 onFirstFocus: function() {
14711 this.buttons.each(function(item){
14715 toggleSourceEdit : function(sourceEditMode){
14718 if(sourceEditMode){
14719 Roo.log("disabling buttons");
14720 this.buttons.each( function(item){
14721 if(item.cmd != 'pencil'){
14727 Roo.log("enabling buttons");
14728 if(this.editorcore.initialized){
14729 this.buttons.each( function(item){
14735 Roo.log("calling toggole on editor");
14736 // tell the editor that it's been pressed..
14737 this.editor.toggleSourceEdit(sourceEditMode);
14747 * @class Roo.bootstrap.Table.AbstractSelectionModel
14748 * @extends Roo.util.Observable
14749 * Abstract base class for grid SelectionModels. It provides the interface that should be
14750 * implemented by descendant classes. This class should not be directly instantiated.
14753 Roo.bootstrap.Table.AbstractSelectionModel = function(){
14754 this.locked = false;
14755 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
14759 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
14760 /** @ignore Called by the grid automatically. Do not call directly. */
14761 init : function(grid){
14767 * Locks the selections.
14770 this.locked = true;
14774 * Unlocks the selections.
14776 unlock : function(){
14777 this.locked = false;
14781 * Returns true if the selections are locked.
14782 * @return {Boolean}
14784 isLocked : function(){
14785 return this.locked;
14789 * @class Roo.bootstrap.Table.ColumnModel
14790 * @extends Roo.util.Observable
14791 * This is the default implementation of a ColumnModel used by the bootstrap table. It defines
14792 * the columns in the table.
14795 * @param {Object} config An Array of column config objects. See this class's
14796 * config objects for details.
14798 Roo.bootstrap.Table.ColumnModel = function(config){
14800 * The config passed into the constructor
14802 this.config = config;
14805 // if no id, create one
14806 // if the column does not have a dataIndex mapping,
14807 // map it to the order it is in the config
14808 for(var i = 0, len = config.length; i < len; i++){
14810 if(typeof c.dataIndex == "undefined"){
14813 if(typeof c.renderer == "string"){
14814 c.renderer = Roo.util.Format[c.renderer];
14816 if(typeof c.id == "undefined"){
14819 // if(c.editor && c.editor.xtype){
14820 // c.editor = Roo.factory(c.editor, Roo.grid);
14822 // if(c.editor && c.editor.isFormField){
14823 // c.editor = new Roo.grid.GridEditor(c.editor);
14826 this.lookup[c.id] = c;
14830 * The width of columns which have no width specified (defaults to 100)
14833 this.defaultWidth = 100;
14836 * Default sortable of columns which have no sortable specified (defaults to false)
14839 this.defaultSortable = false;
14843 * @event widthchange
14844 * Fires when the width of a column changes.
14845 * @param {ColumnModel} this
14846 * @param {Number} columnIndex The column index
14847 * @param {Number} newWidth The new width
14849 "widthchange": true,
14851 * @event headerchange
14852 * Fires when the text of a header changes.
14853 * @param {ColumnModel} this
14854 * @param {Number} columnIndex The column index
14855 * @param {Number} newText The new header text
14857 "headerchange": true,
14859 * @event hiddenchange
14860 * Fires when a column is hidden or "unhidden".
14861 * @param {ColumnModel} this
14862 * @param {Number} columnIndex The column index
14863 * @param {Boolean} hidden true if hidden, false otherwise
14865 "hiddenchange": true,
14867 * @event columnmoved
14868 * Fires when a column is moved.
14869 * @param {ColumnModel} this
14870 * @param {Number} oldIndex
14871 * @param {Number} newIndex
14873 "columnmoved" : true,
14875 * @event columlockchange
14876 * Fires when a column's locked state is changed
14877 * @param {ColumnModel} this
14878 * @param {Number} colIndex
14879 * @param {Boolean} locked true if locked
14881 "columnlockchange" : true
14883 Roo.bootstrap.Table.ColumnModel.superclass.constructor.call(this);
14885 Roo.extend(Roo.bootstrap.Table.ColumnModel, Roo.util.Observable, {
14887 * @cfg {String} header The header text to display in the Grid view.
14890 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
14891 * {@link Roo.data.Record} definition from which to draw the column's value. If not
14892 * specified, the column's index is used as an index into the Record's data Array.
14895 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
14896 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
14899 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
14900 * Defaults to the value of the {@link #defaultSortable} property.
14901 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
14904 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
14907 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
14910 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
14913 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
14916 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
14917 * given the cell's data value. See {@link #setRenderer}. If not specified, the
14918 * default renderer uses the raw data value.
14921 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
14925 * Returns the id of the column at the specified index.
14926 * @param {Number} index The column index
14927 * @return {String} the id
14929 getColumnId : function(index){
14930 return this.config[index].id;
14934 * Returns the column for a specified id.
14935 * @param {String} id The column id
14936 * @return {Object} the column
14938 getColumnById : function(id){
14939 return this.lookup[id];
14944 * Returns the column for a specified dataIndex.
14945 * @param {String} dataIndex The column dataIndex
14946 * @return {Object|Boolean} the column or false if not found
14948 getColumnByDataIndex: function(dataIndex){
14949 var index = this.findColumnIndex(dataIndex);
14950 return index > -1 ? this.config[index] : false;
14954 * Returns the index for a specified column id.
14955 * @param {String} id The column id
14956 * @return {Number} the index, or -1 if not found
14958 getIndexById : function(id){
14959 for(var i = 0, len = this.config.length; i < len; i++){
14960 if(this.config[i].id == id){
14968 * Returns the index for a specified column dataIndex.
14969 * @param {String} dataIndex The column dataIndex
14970 * @return {Number} the index, or -1 if not found
14973 findColumnIndex : function(dataIndex){
14974 for(var i = 0, len = this.config.length; i < len; i++){
14975 if(this.config[i].dataIndex == dataIndex){
14983 moveColumn : function(oldIndex, newIndex){
14984 var c = this.config[oldIndex];
14985 this.config.splice(oldIndex, 1);
14986 this.config.splice(newIndex, 0, c);
14987 this.dataMap = null;
14988 this.fireEvent("columnmoved", this, oldIndex, newIndex);
14991 isLocked : function(colIndex){
14992 return this.config[colIndex].locked === true;
14995 setLocked : function(colIndex, value, suppressEvent){
14996 if(this.isLocked(colIndex) == value){
14999 this.config[colIndex].locked = value;
15000 if(!suppressEvent){
15001 this.fireEvent("columnlockchange", this, colIndex, value);
15005 getTotalLockedWidth : function(){
15006 var totalWidth = 0;
15007 for(var i = 0; i < this.config.length; i++){
15008 if(this.isLocked(i) && !this.isHidden(i)){
15009 this.totalWidth += this.getColumnWidth(i);
15015 getLockedCount : function(){
15016 for(var i = 0, len = this.config.length; i < len; i++){
15017 if(!this.isLocked(i)){
15024 * Returns the number of columns.
15027 getColumnCount : function(visibleOnly){
15028 if(visibleOnly === true){
15030 for(var i = 0, len = this.config.length; i < len; i++){
15031 if(!this.isHidden(i)){
15037 return this.config.length;
15041 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
15042 * @param {Function} fn
15043 * @param {Object} scope (optional)
15044 * @return {Array} result
15046 getColumnsBy : function(fn, scope){
15048 for(var i = 0, len = this.config.length; i < len; i++){
15049 var c = this.config[i];
15050 if(fn.call(scope||this, c, i) === true){
15058 * Returns true if the specified column is sortable.
15059 * @param {Number} col The column index
15060 * @return {Boolean}
15062 isSortable : function(col){
15063 if(typeof this.config[col].sortable == "undefined"){
15064 return this.defaultSortable;
15066 return this.config[col].sortable;
15070 * Returns the rendering (formatting) function defined for the column.
15071 * @param {Number} col The column index.
15072 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
15074 getRenderer : function(col){
15075 if(!this.config[col].renderer){
15076 return Roo.bootstrap.Table.ColumnModel.defaultRenderer;
15078 return this.config[col].renderer;
15082 * Sets the rendering (formatting) function for a column.
15083 * @param {Number} col The column index
15084 * @param {Function} fn The function to use to process the cell's raw data
15085 * to return HTML markup for the grid view. The render function is called with
15086 * the following parameters:<ul>
15087 * <li>Data value.</li>
15088 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
15089 * <li>css A CSS style string to apply to the table cell.</li>
15090 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
15091 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
15092 * <li>Row index</li>
15093 * <li>Column index</li>
15094 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
15096 setRenderer : function(col, fn){
15097 this.config[col].renderer = fn;
15101 * Returns the width for the specified column.
15102 * @param {Number} col The column index
15105 getColumnWidth : function(col){
15106 return this.config[col].width * 1 || this.defaultWidth;
15110 * Sets the width for a column.
15111 * @param {Number} col The column index
15112 * @param {Number} width The new width
15114 setColumnWidth : function(col, width, suppressEvent){
15115 this.config[col].width = width;
15116 this.totalWidth = null;
15117 if(!suppressEvent){
15118 this.fireEvent("widthchange", this, col, width);
15123 * Returns the total width of all columns.
15124 * @param {Boolean} includeHidden True to include hidden column widths
15127 getTotalWidth : function(includeHidden){
15128 if(!this.totalWidth){
15129 this.totalWidth = 0;
15130 for(var i = 0, len = this.config.length; i < len; i++){
15131 if(includeHidden || !this.isHidden(i)){
15132 this.totalWidth += this.getColumnWidth(i);
15136 return this.totalWidth;
15140 * Returns the header for the specified column.
15141 * @param {Number} col The column index
15144 getColumnHeader : function(col){
15145 return this.config[col].header;
15149 * Sets the header for a column.
15150 * @param {Number} col The column index
15151 * @param {String} header The new header
15153 setColumnHeader : function(col, header){
15154 this.config[col].header = header;
15155 this.fireEvent("headerchange", this, col, header);
15159 * Returns the tooltip for the specified column.
15160 * @param {Number} col The column index
15163 getColumnTooltip : function(col){
15164 return this.config[col].tooltip;
15167 * Sets the tooltip for a column.
15168 * @param {Number} col The column index
15169 * @param {String} tooltip The new tooltip
15171 setColumnTooltip : function(col, tooltip){
15172 this.config[col].tooltip = tooltip;
15176 * Returns the dataIndex for the specified column.
15177 * @param {Number} col The column index
15180 getDataIndex : function(col){
15181 return this.config[col].dataIndex;
15185 * Sets the dataIndex for a column.
15186 * @param {Number} col The column index
15187 * @param {Number} dataIndex The new dataIndex
15189 setDataIndex : function(col, dataIndex){
15190 this.config[col].dataIndex = dataIndex;
15196 * Returns true if the cell is editable.
15197 * @param {Number} colIndex The column index
15198 * @param {Number} rowIndex The row index
15199 * @return {Boolean}
15201 isCellEditable : function(colIndex, rowIndex){
15202 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
15206 * Returns the editor defined for the cell/column.
15207 * return false or null to disable editing.
15208 * @param {Number} colIndex The column index
15209 * @param {Number} rowIndex The row index
15212 getCellEditor : function(colIndex, rowIndex){
15213 return this.config[colIndex].editor;
15217 * Sets if a column is editable.
15218 * @param {Number} col The column index
15219 * @param {Boolean} editable True if the column is editable
15221 setEditable : function(col, editable){
15222 this.config[col].editable = editable;
15227 * Returns true if the column is hidden.
15228 * @param {Number} colIndex The column index
15229 * @return {Boolean}
15231 isHidden : function(colIndex){
15232 return this.config[colIndex].hidden;
15237 * Returns true if the column width cannot be changed
15239 isFixed : function(colIndex){
15240 return this.config[colIndex].fixed;
15244 * Returns true if the column can be resized
15245 * @return {Boolean}
15247 isResizable : function(colIndex){
15248 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
15251 * Sets if a column is hidden.
15252 * @param {Number} colIndex The column index
15253 * @param {Boolean} hidden True if the column is hidden
15255 setHidden : function(colIndex, hidden){
15256 this.config[colIndex].hidden = hidden;
15257 this.totalWidth = null;
15258 this.fireEvent("hiddenchange", this, colIndex, hidden);
15262 * Sets the editor for a column.
15263 * @param {Number} col The column index
15264 * @param {Object} editor The editor object
15266 setEditor : function(col, editor){
15267 this.config[col].editor = editor;
15271 Roo.bootstrap.Table.ColumnModel.defaultRenderer = function(value){
15272 if(typeof value == "string" && value.length < 1){
15278 // Alias for backwards compatibility
15279 Roo.bootstrap.Table.DefaultColumnModel = Roo.bootstrap.Table.ColumnModel;
15282 * @extends Roo.bootstrap.Table.AbstractSelectionModel
15283 * @class Roo.bootstrap.Table.RowSelectionModel
15284 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
15285 * It supports multiple selections and keyboard selection/navigation.
15287 * @param {Object} config
15290 Roo.bootstrap.Table.RowSelectionModel = function(config){
15291 Roo.apply(this, config);
15292 this.selections = new Roo.util.MixedCollection(false, function(o){
15297 this.lastActive = false;
15301 * @event selectionchange
15302 * Fires when the selection changes
15303 * @param {SelectionModel} this
15305 "selectionchange" : true,
15307 * @event afterselectionchange
15308 * Fires after the selection changes (eg. by key press or clicking)
15309 * @param {SelectionModel} this
15311 "afterselectionchange" : true,
15313 * @event beforerowselect
15314 * Fires when a row is selected being selected, return false to cancel.
15315 * @param {SelectionModel} this
15316 * @param {Number} rowIndex The selected index
15317 * @param {Boolean} keepExisting False if other selections will be cleared
15319 "beforerowselect" : true,
15322 * Fires when a row is selected.
15323 * @param {SelectionModel} this
15324 * @param {Number} rowIndex The selected index
15325 * @param {Roo.data.Record} r The record
15327 "rowselect" : true,
15329 * @event rowdeselect
15330 * Fires when a row is deselected.
15331 * @param {SelectionModel} this
15332 * @param {Number} rowIndex The selected index
15334 "rowdeselect" : true
15336 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
15337 this.locked = false;
15340 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
15342 * @cfg {Boolean} singleSelect
15343 * True to allow selection of only one row at a time (defaults to false)
15345 singleSelect : false,
15348 initEvents : function(){
15350 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
15351 this.grid.on("mousedown", this.handleMouseDown, this);
15352 }else{ // allow click to work like normal
15353 this.grid.on("rowclick", this.handleDragableRowClick, this);
15356 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
15357 "up" : function(e){
15359 this.selectPrevious(e.shiftKey);
15360 }else if(this.last !== false && this.lastActive !== false){
15361 var last = this.last;
15362 this.selectRange(this.last, this.lastActive-1);
15363 this.grid.getView().focusRow(this.lastActive);
15364 if(last !== false){
15368 this.selectFirstRow();
15370 this.fireEvent("afterselectionchange", this);
15372 "down" : function(e){
15374 this.selectNext(e.shiftKey);
15375 }else if(this.last !== false && this.lastActive !== false){
15376 var last = this.last;
15377 this.selectRange(this.last, this.lastActive+1);
15378 this.grid.getView().focusRow(this.lastActive);
15379 if(last !== false){
15383 this.selectFirstRow();
15385 this.fireEvent("afterselectionchange", this);
15390 var view = this.grid.view;
15391 view.on("refresh", this.onRefresh, this);
15392 view.on("rowupdated", this.onRowUpdated, this);
15393 view.on("rowremoved", this.onRemove, this);
15397 onRefresh : function(){
15398 var ds = this.grid.dataSource, i, v = this.grid.view;
15399 var s = this.selections;
15400 s.each(function(r){
15401 if((i = ds.indexOfId(r.id)) != -1){
15410 onRemove : function(v, index, r){
15411 this.selections.remove(r);
15415 onRowUpdated : function(v, index, r){
15416 if(this.isSelected(r)){
15417 v.onRowSelect(index);
15423 * @param {Array} records The records to select
15424 * @param {Boolean} keepExisting (optional) True to keep existing selections
15426 selectRecords : function(records, keepExisting){
15428 this.clearSelections();
15430 var ds = this.grid.dataSource;
15431 for(var i = 0, len = records.length; i < len; i++){
15432 this.selectRow(ds.indexOf(records[i]), true);
15437 * Gets the number of selected rows.
15440 getCount : function(){
15441 return this.selections.length;
15445 * Selects the first row in the grid.
15447 selectFirstRow : function(){
15452 * Select the last row.
15453 * @param {Boolean} keepExisting (optional) True to keep existing selections
15455 selectLastRow : function(keepExisting){
15456 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
15460 * Selects the row immediately following the last selected row.
15461 * @param {Boolean} keepExisting (optional) True to keep existing selections
15463 selectNext : function(keepExisting){
15464 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
15465 this.selectRow(this.last+1, keepExisting);
15466 this.grid.getView().focusRow(this.last);
15471 * Selects the row that precedes the last selected row.
15472 * @param {Boolean} keepExisting (optional) True to keep existing selections
15474 selectPrevious : function(keepExisting){
15476 this.selectRow(this.last-1, keepExisting);
15477 this.grid.getView().focusRow(this.last);
15482 * Returns the selected records
15483 * @return {Array} Array of selected records
15485 getSelections : function(){
15486 return [].concat(this.selections.items);
15490 * Returns the first selected record.
15493 getSelected : function(){
15494 return this.selections.itemAt(0);
15499 * Clears all selections.
15501 clearSelections : function(fast){
15502 if(this.locked) return;
15504 var ds = this.grid.dataSource;
15505 var s = this.selections;
15506 s.each(function(r){
15507 this.deselectRow(ds.indexOfId(r.id));
15511 this.selections.clear();
15518 * Selects all rows.
15520 selectAll : function(){
15521 if(this.locked) return;
15522 this.selections.clear();
15523 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
15524 this.selectRow(i, true);
15529 * Returns True if there is a selection.
15530 * @return {Boolean}
15532 hasSelection : function(){
15533 return this.selections.length > 0;
15537 * Returns True if the specified row is selected.
15538 * @param {Number/Record} record The record or index of the record to check
15539 * @return {Boolean}
15541 isSelected : function(index){
15542 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
15543 return (r && this.selections.key(r.id) ? true : false);
15547 * Returns True if the specified record id is selected.
15548 * @param {String} id The id of record to check
15549 * @return {Boolean}
15551 isIdSelected : function(id){
15552 return (this.selections.key(id) ? true : false);
15556 handleMouseDown : function(e, t){
15557 var view = this.grid.getView(), rowIndex;
15558 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
15561 if(e.shiftKey && this.last !== false){
15562 var last = this.last;
15563 this.selectRange(last, rowIndex, e.ctrlKey);
15564 this.last = last; // reset the last
15565 view.focusRow(rowIndex);
15567 var isSelected = this.isSelected(rowIndex);
15568 if(e.button !== 0 && isSelected){
15569 view.focusRow(rowIndex);
15570 }else if(e.ctrlKey && isSelected){
15571 this.deselectRow(rowIndex);
15572 }else if(!isSelected){
15573 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
15574 view.focusRow(rowIndex);
15577 this.fireEvent("afterselectionchange", this);
15580 handleDragableRowClick : function(grid, rowIndex, e)
15582 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
15583 this.selectRow(rowIndex, false);
15584 grid.view.focusRow(rowIndex);
15585 this.fireEvent("afterselectionchange", this);
15590 * Selects multiple rows.
15591 * @param {Array} rows Array of the indexes of the row to select
15592 * @param {Boolean} keepExisting (optional) True to keep existing selections
15594 selectRows : function(rows, keepExisting){
15596 this.clearSelections();
15598 for(var i = 0, len = rows.length; i < len; i++){
15599 this.selectRow(rows[i], true);
15604 * Selects a range of rows. All rows in between startRow and endRow are also selected.
15605 * @param {Number} startRow The index of the first row in the range
15606 * @param {Number} endRow The index of the last row in the range
15607 * @param {Boolean} keepExisting (optional) True to retain existing selections
15609 selectRange : function(startRow, endRow, keepExisting){
15610 if(this.locked) return;
15612 this.clearSelections();
15614 if(startRow <= endRow){
15615 for(var i = startRow; i <= endRow; i++){
15616 this.selectRow(i, true);
15619 for(var i = startRow; i >= endRow; i--){
15620 this.selectRow(i, true);
15626 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
15627 * @param {Number} startRow The index of the first row in the range
15628 * @param {Number} endRow The index of the last row in the range
15630 deselectRange : function(startRow, endRow, preventViewNotify){
15631 if(this.locked) return;
15632 for(var i = startRow; i <= endRow; i++){
15633 this.deselectRow(i, preventViewNotify);
15639 * @param {Number} row The index of the row to select
15640 * @param {Boolean} keepExisting (optional) True to keep existing selections
15642 selectRow : function(index, keepExisting, preventViewNotify){
15643 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
15644 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
15645 if(!keepExisting || this.singleSelect){
15646 this.clearSelections();
15648 var r = this.grid.dataSource.getAt(index);
15649 this.selections.add(r);
15650 this.last = this.lastActive = index;
15651 if(!preventViewNotify){
15652 this.grid.getView().onRowSelect(index);
15654 this.fireEvent("rowselect", this, index, r);
15655 this.fireEvent("selectionchange", this);
15661 * @param {Number} row The index of the row to deselect
15663 deselectRow : function(index, preventViewNotify){
15664 if(this.locked) return;
15665 if(this.last == index){
15668 if(this.lastActive == index){
15669 this.lastActive = false;
15671 var r = this.grid.dataSource.getAt(index);
15672 this.selections.remove(r);
15673 if(!preventViewNotify){
15674 this.grid.getView().onRowDeselect(index);
15676 this.fireEvent("rowdeselect", this, index);
15677 this.fireEvent("selectionchange", this);
15681 restoreLast : function(){
15683 this.last = this._last;
15688 acceptsNav : function(row, col, cm){
15689 return !cm.isHidden(col) && cm.isCellEditable(col, row);
15693 onEditorKey : function(field, e){
15694 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
15699 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
15701 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
15703 }else if(k == e.ENTER && !e.ctrlKey){
15707 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
15709 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
15711 }else if(k == e.ESC){
15715 g.startEditing(newCell[0], newCell[1]);
15726 * @class Roo.bootstrap.MessageBar
15727 * @extends Roo.bootstrap.Component
15728 * Bootstrap MessageBar class
15729 * @cfg {String} html contents of the MessageBar
15730 * @cfg {String} weight (info | success | warning | danger) default info
15731 * @cfg {String} beforeClass insert the bar before the given class
15732 * @cfg {Boolean} closable (true | false) default false
15733 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
15736 * Create a new Element
15737 * @param {Object} config The config object
15740 Roo.bootstrap.MessageBar = function(config){
15741 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
15744 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
15750 beforeClass: 'bootstrap-sticky-wrap',
15752 getAutoCreate : function(){
15756 cls: 'alert alert-dismissable alert-' + this.weight,
15761 html: this.html || ''
15767 cfg.cls += ' alert-messages-fixed';
15781 onRender : function(ct, position)
15783 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
15786 var cfg = Roo.apply({}, this.getAutoCreate());
15790 cfg.cls += ' ' + this.cls;
15793 cfg.style = this.style;
15795 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
15797 this.el.setVisibilityMode(Roo.Element.DISPLAY);
15800 this.el.select('>button.close').on('click', this.hide, this);
15806 if (!this.rendered) {
15812 this.fireEvent('show', this);
15818 if (!this.rendered) {
15824 this.fireEvent('hide', this);
15827 update : function()
15829 // var e = this.el.dom.firstChild;
15831 // if(this.closable){
15832 // e = e.nextSibling;
15835 // e.data = this.html || '';
15837 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';