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!!!!');
2955 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
2956 e.on('click', _this.sort, _this);
2958 // this.maskEl = Roo.DomHelper.append(this.el.select('.TableGrid', true).first(), {tag: "div", cls:"x-dlg-mask"}, true);
2959 // this.maskEl.enableDisplayMode("block");
2960 // this.maskEl.show();
2962 this.store.on('load', this.onLoad, this);
2963 this.store.on('beforeload', this.onBeforeLoad, this);
2971 sort : function(e,el)
2973 var col = Roo.get(el)
2974 var sort = col.attr('sort');
2977 if(col.hasClass('glyphicon-arrow-up')){
2981 this.store.sortInfo = {field : sort, direction : dir};
2986 renderHeader : function()
2995 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
2997 var config = cm.config[i];
3001 html: cm.getColumnHeader(i)
3004 if(typeof(config.dataIndex) != 'undefined'){
3005 c.sort = config.dataIndex;
3008 if(typeof(config.sortable) != 'undefined' && config.sortable){
3018 renderBody : function()
3028 renderFooter : function()
3040 Roo.log('ds onload');
3044 var tbody = this.el.select('tbody', true).first();
3048 if(this.store.getCount() > 0){
3049 this.store.data.each(function(d){
3055 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
3056 var renderer = cm.getRenderer(i);
3057 var config = cm.config[i];
3061 if(typeof(renderer) !== 'undefined'){
3062 value = renderer(d.data[cm.getDataIndex(i)], false, d);
3065 if(typeof(value) === 'object'){
3075 html: (typeof(value) === 'object') ? '' : value
3078 if(typeof(config.width) != 'undefined'){
3079 td.width = config.width;
3086 tbody.createChild(row);
3094 Roo.each(renders, function(r){
3095 _this.renderColumn(r);
3099 // if(this.loadMask){
3100 // this.maskEl.hide();
3104 onBeforeLoad : function()
3106 Roo.log('ds onBeforeLoad');
3110 // if(this.loadMask){
3111 // this.maskEl.show();
3117 this.el.select('tbody', true).first().dom.innerHTML = '';
3120 getSelectionModel : function(){
3122 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
3124 return this.selModel;
3127 renderColumn : function(r)
3130 r.cfg.render(Roo.get(r.id));
3133 Roo.each(r.cfg.cn, function(c){
3138 _this.renderColumn(child);
3155 * @class Roo.bootstrap.TableCell
3156 * @extends Roo.bootstrap.Component
3157 * Bootstrap TableCell class
3158 * @cfg {String} html cell contain text
3159 * @cfg {String} cls cell class
3160 * @cfg {String} tag cell tag (td|th) default td
3161 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
3162 * @cfg {String} align Aligns the content in a cell
3163 * @cfg {String} axis Categorizes cells
3164 * @cfg {String} bgcolor Specifies the background color of a cell
3165 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
3166 * @cfg {Number} colspan Specifies the number of columns a cell should span
3167 * @cfg {String} headers Specifies one or more header cells a cell is related to
3168 * @cfg {Number} height Sets the height of a cell
3169 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
3170 * @cfg {Number} rowspan Sets the number of rows a cell should span
3171 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
3172 * @cfg {String} valign Vertical aligns the content in a cell
3173 * @cfg {Number} width Specifies the width of a cell
3176 * Create a new TableCell
3177 * @param {Object} config The config object
3180 Roo.bootstrap.TableCell = function(config){
3181 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
3184 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
3204 getAutoCreate : function(){
3205 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
3225 cfg.align=this.align
3231 cfg.bgcolor=this.bgcolor
3234 cfg.charoff=this.charoff
3237 cfg.colspan=this.colspan
3240 cfg.headers=this.headers
3243 cfg.height=this.height
3246 cfg.nowrap=this.nowrap
3249 cfg.rowspan=this.rowspan
3252 cfg.scope=this.scope
3255 cfg.valign=this.valign
3258 cfg.width=this.width
3277 * @class Roo.bootstrap.TableRow
3278 * @extends Roo.bootstrap.Component
3279 * Bootstrap TableRow class
3280 * @cfg {String} cls row class
3281 * @cfg {String} align Aligns the content in a table row
3282 * @cfg {String} bgcolor Specifies a background color for a table row
3283 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
3284 * @cfg {String} valign Vertical aligns the content in a table row
3287 * Create a new TableRow
3288 * @param {Object} config The config object
3291 Roo.bootstrap.TableRow = function(config){
3292 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
3295 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
3303 getAutoCreate : function(){
3304 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
3314 cfg.align = this.align;
3317 cfg.bgcolor = this.bgcolor;
3320 cfg.charoff = this.charoff;
3323 cfg.valign = this.valign;
3341 * @class Roo.bootstrap.TableBody
3342 * @extends Roo.bootstrap.Component
3343 * Bootstrap TableBody class
3344 * @cfg {String} cls element class
3345 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
3346 * @cfg {String} align Aligns the content inside the element
3347 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
3348 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
3351 * Create a new TableBody
3352 * @param {Object} config The config object
3355 Roo.bootstrap.TableBody = function(config){
3356 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
3359 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
3367 getAutoCreate : function(){
3368 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
3382 cfg.align = this.align;
3385 cfg.charoff = this.charoff;
3388 cfg.valign = this.valign;
3395 // initEvents : function()
3402 // this.store = Roo.factory(this.store, Roo.data);
3403 // this.store.on('load', this.onLoad, this);
3405 // this.store.load();
3409 // onLoad: function ()
3411 // this.fireEvent('load', this);
3421 * Ext JS Library 1.1.1
3422 * Copyright(c) 2006-2007, Ext JS, LLC.
3424 * Originally Released Under LGPL - original licence link has changed is not relivant.
3427 * <script type="text/javascript">
3430 // as we use this in bootstrap.
3431 Roo.namespace('Roo.form');
3433 * @class Roo.form.Action
3434 * Internal Class used to handle form actions
3436 * @param {Roo.form.BasicForm} el The form element or its id
3437 * @param {Object} config Configuration options
3442 // define the action interface
3443 Roo.form.Action = function(form, options){
3445 this.options = options || {};
3448 * Client Validation Failed
3451 Roo.form.Action.CLIENT_INVALID = 'client';
3453 * Server Validation Failed
3456 Roo.form.Action.SERVER_INVALID = 'server';
3458 * Connect to Server Failed
3461 Roo.form.Action.CONNECT_FAILURE = 'connect';
3463 * Reading Data from Server Failed
3466 Roo.form.Action.LOAD_FAILURE = 'load';
3468 Roo.form.Action.prototype = {
3470 failureType : undefined,
3471 response : undefined,
3475 run : function(options){
3480 success : function(response){
3485 handleResponse : function(response){
3489 // default connection failure
3490 failure : function(response){
3492 this.response = response;
3493 this.failureType = Roo.form.Action.CONNECT_FAILURE;
3494 this.form.afterAction(this, false);
3497 processResponse : function(response){
3498 this.response = response;
3499 if(!response.responseText){
3502 this.result = this.handleResponse(response);
3506 // utility functions used internally
3507 getUrl : function(appendParams){
3508 var url = this.options.url || this.form.url || this.form.el.dom.action;
3510 var p = this.getParams();
3512 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
3518 getMethod : function(){
3519 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
3522 getParams : function(){
3523 var bp = this.form.baseParams;
3524 var p = this.options.params;
3526 if(typeof p == "object"){
3527 p = Roo.urlEncode(Roo.applyIf(p, bp));
3528 }else if(typeof p == 'string' && bp){
3529 p += '&' + Roo.urlEncode(bp);
3532 p = Roo.urlEncode(bp);
3537 createCallback : function(){
3539 success: this.success,
3540 failure: this.failure,
3542 timeout: (this.form.timeout*1000),
3543 upload: this.form.fileUpload ? this.success : undefined
3548 Roo.form.Action.Submit = function(form, options){
3549 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
3552 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
3555 haveProgress : false,
3556 uploadComplete : false,
3558 // uploadProgress indicator.
3559 uploadProgress : function()
3561 if (!this.form.progressUrl) {
3565 if (!this.haveProgress) {
3566 Roo.MessageBox.progress("Uploading", "Uploading");
3568 if (this.uploadComplete) {
3569 Roo.MessageBox.hide();
3573 this.haveProgress = true;
3575 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
3577 var c = new Roo.data.Connection();
3579 url : this.form.progressUrl,
3584 success : function(req){
3585 //console.log(data);
3589 rdata = Roo.decode(req.responseText)
3591 Roo.log("Invalid data from server..");
3595 if (!rdata || !rdata.success) {
3597 Roo.MessageBox.alert(Roo.encode(rdata));
3600 var data = rdata.data;
3602 if (this.uploadComplete) {
3603 Roo.MessageBox.hide();
3608 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
3609 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
3612 this.uploadProgress.defer(2000,this);
3615 failure: function(data) {
3616 Roo.log('progress url failed ');
3627 // run get Values on the form, so it syncs any secondary forms.
3628 this.form.getValues();
3630 var o = this.options;
3631 var method = this.getMethod();
3632 var isPost = method == 'POST';
3633 if(o.clientValidation === false || this.form.isValid()){
3635 if (this.form.progressUrl) {
3636 this.form.findField('UPLOAD_IDENTIFIER').setValue(
3637 (new Date() * 1) + '' + Math.random());
3642 Roo.Ajax.request(Roo.apply(this.createCallback(), {
3643 form:this.form.el.dom,
3644 url:this.getUrl(!isPost),
3646 params:isPost ? this.getParams() : null,
3647 isUpload: this.form.fileUpload
3650 this.uploadProgress();
3652 }else if (o.clientValidation !== false){ // client validation failed
3653 this.failureType = Roo.form.Action.CLIENT_INVALID;
3654 this.form.afterAction(this, false);
3658 success : function(response)
3660 this.uploadComplete= true;
3661 if (this.haveProgress) {
3662 Roo.MessageBox.hide();
3666 var result = this.processResponse(response);
3667 if(result === true || result.success){
3668 this.form.afterAction(this, true);
3672 this.form.markInvalid(result.errors);
3673 this.failureType = Roo.form.Action.SERVER_INVALID;
3675 this.form.afterAction(this, false);
3677 failure : function(response)
3679 this.uploadComplete= true;
3680 if (this.haveProgress) {
3681 Roo.MessageBox.hide();
3684 this.response = response;
3685 this.failureType = Roo.form.Action.CONNECT_FAILURE;
3686 this.form.afterAction(this, false);
3689 handleResponse : function(response){
3690 if(this.form.errorReader){
3691 var rs = this.form.errorReader.read(response);
3694 for(var i = 0, len = rs.records.length; i < len; i++) {
3695 var r = rs.records[i];
3699 if(errors.length < 1){
3703 success : rs.success,
3709 ret = Roo.decode(response.responseText);
3713 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
3723 Roo.form.Action.Load = function(form, options){
3724 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
3725 this.reader = this.form.reader;
3728 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
3733 Roo.Ajax.request(Roo.apply(
3734 this.createCallback(), {
3735 method:this.getMethod(),
3736 url:this.getUrl(false),
3737 params:this.getParams()
3741 success : function(response){
3743 var result = this.processResponse(response);
3744 if(result === true || !result.success || !result.data){
3745 this.failureType = Roo.form.Action.LOAD_FAILURE;
3746 this.form.afterAction(this, false);
3749 this.form.clearInvalid();
3750 this.form.setValues(result.data);
3751 this.form.afterAction(this, true);
3754 handleResponse : function(response){
3755 if(this.form.reader){
3756 var rs = this.form.reader.read(response);
3757 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
3759 success : rs.success,
3763 return Roo.decode(response.responseText);
3767 Roo.form.Action.ACTION_TYPES = {
3768 'load' : Roo.form.Action.Load,
3769 'submit' : Roo.form.Action.Submit
3778 * @class Roo.bootstrap.Form
3779 * @extends Roo.bootstrap.Component
3780 * Bootstrap Form class
3781 * @cfg {String} method GET | POST (default POST)
3782 * @cfg {String} labelAlign top | left (default top)
3783 * @cfg {String} align left | right - for navbars
3788 * @param {Object} config The config object
3792 Roo.bootstrap.Form = function(config){
3793 Roo.bootstrap.Form.superclass.constructor.call(this, config);
3796 * @event clientvalidation
3797 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
3798 * @param {Form} this
3799 * @param {Boolean} valid true if the form has passed client-side validation
3801 clientvalidation: true,
3803 * @event beforeaction
3804 * Fires before any action is performed. Return false to cancel the action.
3805 * @param {Form} this
3806 * @param {Action} action The action to be performed
3810 * @event actionfailed
3811 * Fires when an action fails.
3812 * @param {Form} this
3813 * @param {Action} action The action that failed
3815 actionfailed : true,
3817 * @event actioncomplete
3818 * Fires when an action is completed.
3819 * @param {Form} this
3820 * @param {Action} action The action that completed
3822 actioncomplete : true
3827 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
3830 * @cfg {String} method
3831 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
3836 * The URL to use for form actions if one isn't supplied in the action options.
3839 * @cfg {Boolean} fileUpload
3840 * Set to true if this form is a file upload.
3844 * @cfg {Object} baseParams
3845 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
3849 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
3853 * @cfg {Sting} align (left|right) for navbar forms
3858 activeAction : null,
3861 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
3862 * element by passing it or its id or mask the form itself by passing in true.
3865 waitMsgTarget : false,
3870 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
3871 * element by passing it or its id or mask the form itself by passing in true.
3875 getAutoCreate : function(){
3879 method : this.method || 'POST',
3880 id : this.id || Roo.id(),
3883 if (this.parent().xtype.match(/^Nav/)) {
3884 cfg.cls = 'navbar-form navbar-' + this.align;
3888 if (this.labelAlign == 'left' ) {
3889 cfg.cls += ' form-horizontal';
3895 initEvents : function()
3897 this.el.on('submit', this.onSubmit, this);
3902 onSubmit : function(e){
3907 * Returns true if client-side validation on the form is successful.
3910 isValid : function(){
3911 var items = this.getItems();
3913 items.each(function(f){
3922 * Returns true if any fields in this form have changed since their original load.
3925 isDirty : function(){
3927 var items = this.getItems();
3928 items.each(function(f){
3938 * Performs a predefined action (submit or load) or custom actions you define on this form.
3939 * @param {String} actionName The name of the action type
3940 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
3941 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
3942 * accept other config options):
3944 Property Type Description
3945 ---------------- --------------- ----------------------------------------------------------------------------------
3946 url String The url for the action (defaults to the form's url)
3947 method String The form method to use (defaults to the form's method, or POST if not defined)
3948 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
3949 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
3950 validate the form on the client (defaults to false)
3952 * @return {BasicForm} this
3954 doAction : function(action, options){
3955 if(typeof action == 'string'){
3956 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
3958 if(this.fireEvent('beforeaction', this, action) !== false){
3959 this.beforeAction(action);
3960 action.run.defer(100, action);
3966 beforeAction : function(action){
3967 var o = action.options;
3969 // not really supported yet.. ??
3971 //if(this.waitMsgTarget === true){
3972 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
3973 //}else if(this.waitMsgTarget){
3974 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
3975 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
3977 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
3983 afterAction : function(action, success){
3984 this.activeAction = null;
3985 var o = action.options;
3987 //if(this.waitMsgTarget === true){
3989 //}else if(this.waitMsgTarget){
3990 // this.waitMsgTarget.unmask();
3992 // Roo.MessageBox.updateProgress(1);
3993 // Roo.MessageBox.hide();
4000 Roo.callback(o.success, o.scope, [this, action]);
4001 this.fireEvent('actioncomplete', this, action);
4005 // failure condition..
4006 // we have a scenario where updates need confirming.
4007 // eg. if a locking scenario exists..
4008 // we look for { errors : { needs_confirm : true }} in the response.
4010 (typeof(action.result) != 'undefined') &&
4011 (typeof(action.result.errors) != 'undefined') &&
4012 (typeof(action.result.errors.needs_confirm) != 'undefined')
4015 Roo.log("not supported yet");
4018 Roo.MessageBox.confirm(
4019 "Change requires confirmation",
4020 action.result.errorMsg,
4025 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
4035 Roo.callback(o.failure, o.scope, [this, action]);
4036 // show an error message if no failed handler is set..
4037 if (!this.hasListener('actionfailed')) {
4038 Roo.log("need to add dialog support");
4040 Roo.MessageBox.alert("Error",
4041 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
4042 action.result.errorMsg :
4043 "Saving Failed, please check your entries or try again"
4048 this.fireEvent('actionfailed', this, action);
4053 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
4054 * @param {String} id The value to search for
4057 findField : function(id){
4058 var items = this.getItems();
4059 var field = items.get(id);
4061 items.each(function(f){
4062 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
4069 return field || null;
4072 * Mark fields in this form invalid in bulk.
4073 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
4074 * @return {BasicForm} this
4076 markInvalid : function(errors){
4077 if(errors instanceof Array){
4078 for(var i = 0, len = errors.length; i < len; i++){
4079 var fieldError = errors[i];
4080 var f = this.findField(fieldError.id);
4082 f.markInvalid(fieldError.msg);
4088 if(typeof errors[id] != 'function' && (field = this.findField(id))){
4089 field.markInvalid(errors[id]);
4093 //Roo.each(this.childForms || [], function (f) {
4094 // f.markInvalid(errors);
4101 * Set values for fields in this form in bulk.
4102 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
4103 * @return {BasicForm} this
4105 setValues : function(values){
4106 if(values instanceof Array){ // array of objects
4107 for(var i = 0, len = values.length; i < len; i++){
4109 var f = this.findField(v.id);
4111 f.setValue(v.value);
4112 if(this.trackResetOnLoad){
4113 f.originalValue = f.getValue();
4117 }else{ // object hash
4120 if(typeof values[id] != 'function' && (field = this.findField(id))){
4122 if (field.setFromData &&
4124 field.displayField &&
4125 // combos' with local stores can
4126 // be queried via setValue()
4127 // to set their value..
4128 (field.store && !field.store.isLocal)
4132 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
4133 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
4134 field.setFromData(sd);
4137 field.setValue(values[id]);
4141 if(this.trackResetOnLoad){
4142 field.originalValue = field.getValue();
4148 //Roo.each(this.childForms || [], function (f) {
4149 // f.setValues(values);
4156 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
4157 * they are returned as an array.
4158 * @param {Boolean} asString
4161 getValues : function(asString){
4162 //if (this.childForms) {
4163 // copy values from the child forms
4164 // Roo.each(this.childForms, function (f) {
4165 // this.setValues(f.getValues());
4171 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
4172 if(asString === true){
4175 return Roo.urlDecode(fs);
4179 * Returns the fields in this form as an object with key/value pairs.
4180 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
4183 getFieldValues : function(with_hidden)
4185 var items = this.getItems();
4187 items.each(function(f){
4191 var v = f.getValue();
4192 if (f.inputType =='radio') {
4193 if (typeof(ret[f.getName()]) == 'undefined') {
4194 ret[f.getName()] = ''; // empty..
4197 if (!f.el.dom.checked) {
4205 // not sure if this supported any more..
4206 if ((typeof(v) == 'object') && f.getRawValue) {
4207 v = f.getRawValue() ; // dates..
4209 // combo boxes where name != hiddenName...
4210 if (f.name != f.getName()) {
4211 ret[f.name] = f.getRawValue();
4213 ret[f.getName()] = v;
4220 * Clears all invalid messages in this form.
4221 * @return {BasicForm} this
4223 clearInvalid : function(){
4224 var items = this.getItems();
4226 items.each(function(f){
4237 * @return {BasicForm} this
4240 var items = this.getItems();
4241 items.each(function(f){
4245 Roo.each(this.childForms || [], function (f) {
4252 getItems : function()
4254 var r=new Roo.util.MixedCollection(false, function(o){
4255 return o.id || (o.id = Roo.id());
4257 var iter = function(el) {
4264 Roo.each(el.items,function(e) {
4283 * Ext JS Library 1.1.1
4284 * Copyright(c) 2006-2007, Ext JS, LLC.
4286 * Originally Released Under LGPL - original licence link has changed is not relivant.
4289 * <script type="text/javascript">
4292 * @class Roo.form.VTypes
4293 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
4296 Roo.form.VTypes = function(){
4297 // closure these in so they are only created once.
4298 var alpha = /^[a-zA-Z_]+$/;
4299 var alphanum = /^[a-zA-Z0-9_]+$/;
4300 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
4301 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
4303 // All these messages and functions are configurable
4306 * The function used to validate email addresses
4307 * @param {String} value The email address
4309 'email' : function(v){
4310 return email.test(v);
4313 * The error text to display when the email validation function returns false
4316 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
4318 * The keystroke filter mask to be applied on email input
4321 'emailMask' : /[a-z0-9_\.\-@]/i,
4324 * The function used to validate URLs
4325 * @param {String} value The URL
4327 'url' : function(v){
4331 * The error text to display when the url validation function returns false
4334 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
4337 * The function used to validate alpha values
4338 * @param {String} value The value
4340 'alpha' : function(v){
4341 return alpha.test(v);
4344 * The error text to display when the alpha validation function returns false
4347 'alphaText' : 'This field should only contain letters and _',
4349 * The keystroke filter mask to be applied on alpha input
4352 'alphaMask' : /[a-z_]/i,
4355 * The function used to validate alphanumeric values
4356 * @param {String} value The value
4358 'alphanum' : function(v){
4359 return alphanum.test(v);
4362 * The error text to display when the alphanumeric validation function returns false
4365 'alphanumText' : 'This field should only contain letters, numbers and _',
4367 * The keystroke filter mask to be applied on alphanumeric input
4370 'alphanumMask' : /[a-z0-9_]/i
4380 * @class Roo.bootstrap.Input
4381 * @extends Roo.bootstrap.Component
4382 * Bootstrap Input class
4383 * @cfg {Boolean} disabled is it disabled
4384 * @cfg {String} fieldLabel - the label associated
4385 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
4386 * @cfg {String} name name of the input
4387 * @cfg {string} fieldLabel - the label associated
4388 * @cfg {string} inputType - input / file submit ...
4389 * @cfg {string} placeholder - placeholder to put in text.
4390 * @cfg {string} before - input group add on before
4391 * @cfg {string} after - input group add on after
4392 * @cfg {string} size - (lg|sm) or leave empty..
4393 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
4394 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
4395 * @cfg {Number} md colspan out of 12 for computer-sized screens
4396 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
4397 * @cfg {string} value default value of the input
4398 * @cfg {Number} labelWidth set the width of label (0-12)
4399 * @cfg {String} labelAlign (top|left)
4400 * @cfg {Boolean} readOnly Specifies that the field should be read-only
4404 * Create a new Input
4405 * @param {Object} config The config object
4408 Roo.bootstrap.Input = function(config){
4409 Roo.bootstrap.Input.superclass.constructor.call(this, config);
4414 * Fires when this field receives input focus.
4415 * @param {Roo.form.Field} this
4420 * Fires when this field loses input focus.
4421 * @param {Roo.form.Field} this
4426 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
4427 * {@link Roo.EventObject#getKey} to determine which key was pressed.
4428 * @param {Roo.form.Field} this
4429 * @param {Roo.EventObject} e The event object
4434 * Fires just before the field blurs if the field value has changed.
4435 * @param {Roo.form.Field} this
4436 * @param {Mixed} newValue The new value
4437 * @param {Mixed} oldValue The original value
4442 * Fires after the field has been marked as invalid.
4443 * @param {Roo.form.Field} this
4444 * @param {String} msg The validation message
4449 * Fires after the field has been validated with no errors.
4450 * @param {Roo.form.Field} this
4455 * Fires after the key up
4456 * @param {Roo.form.Field} this
4457 * @param {Roo.EventObject} e The event Object
4463 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
4465 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
4466 automatic validation (defaults to "keyup").
4468 validationEvent : "keyup",
4470 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
4472 validateOnBlur : true,
4474 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
4476 validationDelay : 250,
4478 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
4480 focusClass : "x-form-focus", // not needed???
4484 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
4486 invalidClass : "has-error",
4489 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
4491 selectOnFocus : false,
4494 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
4498 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
4503 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
4505 disableKeyFilter : false,
4508 * @cfg {Boolean} disabled True to disable the field (defaults to false).
4512 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
4516 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
4518 blankText : "This field is required",
4521 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
4525 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
4527 maxLength : Number.MAX_VALUE,
4529 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
4531 minLengthText : "The minimum length for this field is {0}",
4533 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
4535 maxLengthText : "The maximum length for this field is {0}",
4539 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
4540 * If available, this function will be called only after the basic validators all return true, and will be passed the
4541 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
4545 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
4546 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
4547 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
4551 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
4574 parentLabelAlign : function()
4577 while (parent.parent()) {
4578 parent = parent.parent();
4579 if (typeof(parent.labelAlign) !='undefined') {
4580 return parent.labelAlign;
4587 getAutoCreate : function(){
4589 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
4595 if(this.inputType != 'hidden'){
4596 cfg.cls = 'form-group' //input-group
4602 type : this.inputType,
4604 cls : 'form-control',
4605 placeholder : this.placeholder || ''
4609 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
4610 input.maxLength = this.maxLength;
4613 if (this.disabled) {
4614 input.disabled=true;
4617 if (this.readOnly) {
4618 input.readonly=true;
4622 input.name = this.name;
4625 input.cls += ' input-' + this.size;
4628 ['xs','sm','md','lg'].map(function(size){
4629 if (settings[size]) {
4630 cfg.cls += ' col-' + size + '-' + settings[size];
4634 var inputblock = input;
4636 if (this.before || this.after) {
4639 cls : 'input-group',
4643 inputblock.cn.push({
4645 cls : 'input-group-addon',
4649 inputblock.cn.push(input);
4651 inputblock.cn.push({
4653 cls : 'input-group-addon',
4660 if (align ==='left' && this.fieldLabel.length) {
4661 Roo.log("left and has label");
4667 cls : 'control-label col-sm-' + this.labelWidth,
4668 html : this.fieldLabel
4672 cls : "col-sm-" + (12 - this.labelWidth),
4679 } else if ( this.fieldLabel.length) {
4685 //cls : 'input-group-addon',
4686 html : this.fieldLabel
4696 Roo.log(" no label && no align");
4705 Roo.log('input-parentType: ' + this.parentType);
4707 if (this.parentType === 'Navbar' && this.parent().bar) {
4708 cfg.cls += ' navbar-form';
4716 * return the real input element.
4718 inputEl: function ()
4720 return this.el.select('input.form-control',true).first();
4722 setDisabled : function(v)
4724 var i = this.inputEl().dom;
4726 i.removeAttribute('disabled');
4730 i.setAttribute('disabled','true');
4732 initEvents : function()
4735 this.inputEl().on("keydown" , this.fireKey, this);
4736 this.inputEl().on("focus", this.onFocus, this);
4737 this.inputEl().on("blur", this.onBlur, this);
4739 this.inputEl().relayEvent('keyup', this);
4741 // reference to original value for reset
4742 this.originalValue = this.getValue();
4743 //Roo.form.TextField.superclass.initEvents.call(this);
4744 if(this.validationEvent == 'keyup'){
4745 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
4746 this.inputEl().on('keyup', this.filterValidation, this);
4748 else if(this.validationEvent !== false){
4749 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
4752 if(this.selectOnFocus){
4753 this.on("focus", this.preFocus, this);
4756 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
4757 this.inputEl().on("keypress", this.filterKeys, this);
4760 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
4761 this.el.on("click", this.autoSize, this);
4764 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
4765 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
4769 filterValidation : function(e){
4770 if(!e.isNavKeyPress()){
4771 this.validationTask.delay(this.validationDelay);
4775 * Validates the field value
4776 * @return {Boolean} True if the value is valid, else false
4778 validate : function(){
4779 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
4780 if(this.disabled || this.validateValue(this.getRawValue())){
4781 this.clearInvalid();
4789 * Validates a value according to the field's validation rules and marks the field as invalid
4790 * if the validation fails
4791 * @param {Mixed} value The value to validate
4792 * @return {Boolean} True if the value is valid, else false
4794 validateValue : function(value){
4795 if(value.length < 1) { // if it's blank
4796 if(this.allowBlank){
4797 this.clearInvalid();
4800 this.markInvalid(this.blankText);
4804 if(value.length < this.minLength){
4805 this.markInvalid(String.format(this.minLengthText, this.minLength));
4808 if(value.length > this.maxLength){
4809 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
4813 var vt = Roo.form.VTypes;
4814 if(!vt[this.vtype](value, this)){
4815 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
4819 if(typeof this.validator == "function"){
4820 var msg = this.validator(value);
4822 this.markInvalid(msg);
4826 if(this.regex && !this.regex.test(value)){
4827 this.markInvalid(this.regexText);
4836 fireKey : function(e){
4837 //Roo.log('field ' + e.getKey());
4838 if(e.isNavKeyPress()){
4839 this.fireEvent("specialkey", this, e);
4842 focus : function (selectText){
4844 this.inputEl().focus();
4845 if(selectText === true){
4846 this.inputEl().dom.select();
4852 onFocus : function(){
4853 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
4854 // this.el.addClass(this.focusClass);
4857 this.hasFocus = true;
4858 this.startValue = this.getValue();
4859 this.fireEvent("focus", this);
4863 beforeBlur : Roo.emptyFn,
4867 onBlur : function(){
4869 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
4870 //this.el.removeClass(this.focusClass);
4872 this.hasFocus = false;
4873 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
4876 var v = this.getValue();
4877 if(String(v) !== String(this.startValue)){
4878 this.fireEvent('change', this, v, this.startValue);
4880 this.fireEvent("blur", this);
4884 * Resets the current field value to the originally loaded value and clears any validation messages
4887 this.setValue(this.originalValue);
4888 this.clearInvalid();
4891 * Returns the name of the field
4892 * @return {Mixed} name The name field
4894 getName: function(){
4898 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
4899 * @return {Mixed} value The field value
4901 getValue : function(){
4902 return this.inputEl().getValue();
4905 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
4906 * @return {Mixed} value The field value
4908 getRawValue : function(){
4909 var v = this.inputEl().getValue();
4915 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
4916 * @param {Mixed} value The value to set
4918 setRawValue : function(v){
4919 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
4922 selectText : function(start, end){
4923 var v = this.getRawValue();
4925 start = start === undefined ? 0 : start;
4926 end = end === undefined ? v.length : end;
4927 var d = this.inputEl().dom;
4928 if(d.setSelectionRange){
4929 d.setSelectionRange(start, end);
4930 }else if(d.createTextRange){
4931 var range = d.createTextRange();
4932 range.moveStart("character", start);
4933 range.moveEnd("character", v.length-end);
4940 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
4941 * @param {Mixed} value The value to set
4943 setValue : function(v){
4946 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
4952 processValue : function(value){
4953 if(this.stripCharsRe){
4954 var newValue = value.replace(this.stripCharsRe, '');
4955 if(newValue !== value){
4956 this.setRawValue(newValue);
4963 preFocus : function(){
4965 if(this.selectOnFocus){
4966 this.inputEl().dom.select();
4969 filterKeys : function(e){
4971 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
4974 var c = e.getCharCode(), cc = String.fromCharCode(c);
4975 if(Roo.isIE && (e.isSpecialKey() || !cc)){
4978 if(!this.maskRe.test(cc)){
4983 * Clear any invalid styles/messages for this field
4985 clearInvalid : function(){
4987 if(!this.el || this.preventMark){ // not rendered
4990 this.el.removeClass(this.invalidClass);
4992 switch(this.msgTarget){
4994 this.el.dom.qtip = '';
4997 this.el.dom.title = '';
5001 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
5006 this.errorIcon.dom.qtip = '';
5007 this.errorIcon.hide();
5008 this.un('resize', this.alignErrorIcon, this);
5012 var t = Roo.getDom(this.msgTarget);
5014 t.style.display = 'none';
5018 this.fireEvent('valid', this);
5021 * Mark this field as invalid
5022 * @param {String} msg The validation message
5024 markInvalid : function(msg){
5025 if(!this.el || this.preventMark){ // not rendered
5028 this.el.addClass(this.invalidClass);
5030 msg = msg || this.invalidText;
5031 switch(this.msgTarget){
5033 this.el.dom.qtip = msg;
5034 this.el.dom.qclass = 'x-form-invalid-tip';
5035 if(Roo.QuickTips){ // fix for floating editors interacting with DND
5036 Roo.QuickTips.enable();
5040 this.el.dom.title = msg;
5044 var elp = this.el.findParent('.x-form-element', 5, true);
5045 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
5046 this.errorEl.setWidth(elp.getWidth(true)-20);
5048 this.errorEl.update(msg);
5049 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
5052 if(!this.errorIcon){
5053 var elp = this.el.findParent('.x-form-element', 5, true);
5054 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
5056 this.alignErrorIcon();
5057 this.errorIcon.dom.qtip = msg;
5058 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
5059 this.errorIcon.show();
5060 this.on('resize', this.alignErrorIcon, this);
5063 var t = Roo.getDom(this.msgTarget);
5065 t.style.display = this.msgDisplay;
5069 this.fireEvent('invalid', this, msg);
5072 SafariOnKeyDown : function(event)
5074 // this is a workaround for a password hang bug on chrome/ webkit.
5076 var isSelectAll = false;
5078 if(this.inputEl().dom.selectionEnd > 0){
5079 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
5081 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
5082 event.preventDefault();
5087 if(isSelectAll){ // backspace and delete key
5089 event.preventDefault();
5090 // this is very hacky as keydown always get's upper case.
5092 var cc = String.fromCharCode(event.getCharCode());
5093 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
5097 adjustWidth : function(tag, w){
5098 tag = tag.toLowerCase();
5099 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
5100 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
5104 if(tag == 'textarea'){
5107 }else if(Roo.isOpera){
5111 if(tag == 'textarea'){
5130 * @class Roo.bootstrap.TextArea
5131 * @extends Roo.bootstrap.Input
5132 * Bootstrap TextArea class
5133 * @cfg {Number} cols Specifies the visible width of a text area
5134 * @cfg {Number} rows Specifies the visible number of lines in a text area
5135 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
5136 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
5137 * @cfg {string} html text
5140 * Create a new TextArea
5141 * @param {Object} config The config object
5144 Roo.bootstrap.TextArea = function(config){
5145 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
5149 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
5159 getAutoCreate : function(){
5161 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
5172 value : this.value || '',
5173 html: this.html || '',
5174 cls : 'form-control',
5175 placeholder : this.placeholder || ''
5179 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
5180 input.maxLength = this.maxLength;
5184 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
5188 input.cols = this.cols;
5191 if (this.readOnly) {
5192 input.readonly = true;
5196 input.name = this.name;
5200 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
5204 ['xs','sm','md','lg'].map(function(size){
5205 if (settings[size]) {
5206 cfg.cls += ' col-' + size + '-' + settings[size];
5210 var inputblock = input;
5212 if (this.before || this.after) {
5215 cls : 'input-group',
5219 inputblock.cn.push({
5221 cls : 'input-group-addon',
5225 inputblock.cn.push(input);
5227 inputblock.cn.push({
5229 cls : 'input-group-addon',
5236 if (align ==='left' && this.fieldLabel.length) {
5237 Roo.log("left and has label");
5243 cls : 'control-label col-sm-' + this.labelWidth,
5244 html : this.fieldLabel
5248 cls : "col-sm-" + (12 - this.labelWidth),
5255 } else if ( this.fieldLabel.length) {
5261 //cls : 'input-group-addon',
5262 html : this.fieldLabel
5272 Roo.log(" no label && no align");
5282 if (this.disabled) {
5283 input.disabled=true;
5290 * return the real textarea element.
5292 inputEl: function ()
5294 return this.el.select('textarea.form-control',true).first();
5302 * trigger field - base class for combo..
5307 * @class Roo.bootstrap.TriggerField
5308 * @extends Roo.bootstrap.Input
5309 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
5310 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
5311 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
5312 * for which you can provide a custom implementation. For example:
5314 var trigger = new Roo.bootstrap.TriggerField();
5315 trigger.onTriggerClick = myTriggerFn;
5316 trigger.applyTo('my-field');
5319 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
5320 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
5321 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
5322 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
5324 * Create a new TriggerField.
5325 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
5326 * to the base TextField)
5328 Roo.bootstrap.TriggerField = function(config){
5329 this.mimicing = false;
5330 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
5333 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
5335 * @cfg {String} triggerClass A CSS class to apply to the trigger
5338 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
5342 /** @cfg {Boolean} grow @hide */
5343 /** @cfg {Number} growMin @hide */
5344 /** @cfg {Number} growMax @hide */
5350 autoSize: Roo.emptyFn,
5357 actionMode : 'wrap',
5361 getAutoCreate : function(){
5363 var parent = this.parent();
5365 var align = this.parentLabelAlign();
5370 cls: 'form-group' //input-group
5377 type : this.inputType,
5378 cls : 'form-control',
5379 autocomplete: 'off',
5380 placeholder : this.placeholder || ''
5384 input.name = this.name;
5387 input.cls += ' input-' + this.size;
5390 if (this.disabled) {
5391 input.disabled=true;
5394 var inputblock = input;
5396 if (this.before || this.after) {
5399 cls : 'input-group',
5403 inputblock.cn.push({
5405 cls : 'input-group-addon',
5409 inputblock.cn.push(input);
5411 inputblock.cn.push({
5413 cls : 'input-group-addon',
5426 cls: 'form-hidden-field'
5434 Roo.log('multiple');
5442 cls: 'form-hidden-field'
5446 cls: 'select2-choices',
5450 cls: 'select2-search-field',
5463 cls: 'select2-container input-group',
5468 cls: 'typeahead typeahead-long dropdown-menu',
5469 style: 'display:none'
5477 cls : 'input-group-addon btn dropdown-toggle',
5485 cls: 'combobox-clear',
5499 combobox.cls += ' select2-container-multi';
5502 if (align ==='left' && this.fieldLabel.length) {
5504 Roo.log("left and has label");
5510 cls : 'control-label col-sm-' + this.labelWidth,
5511 html : this.fieldLabel
5515 cls : "col-sm-" + (12 - this.labelWidth),
5522 } else if ( this.fieldLabel.length) {
5528 //cls : 'input-group-addon',
5529 html : this.fieldLabel
5539 Roo.log(" no label && no align");
5546 ['xs','sm','md','lg'].map(function(size){
5547 if (settings[size]) {
5548 cfg.cls += ' col-' + size + '-' + settings[size];
5559 onResize : function(w, h){
5560 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
5561 // if(typeof w == 'number'){
5562 // var x = w - this.trigger.getWidth();
5563 // this.inputEl().setWidth(this.adjustWidth('input', x));
5564 // this.trigger.setStyle('left', x+'px');
5569 adjustSize : Roo.BoxComponent.prototype.adjustSize,
5572 getResizeEl : function(){
5573 return this.inputEl();
5577 getPositionEl : function(){
5578 return this.inputEl();
5582 alignErrorIcon : function(){
5583 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
5587 initEvents : function(){
5589 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
5590 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
5592 this.trigger = this.el.select('span.dropdown-toggle',true).first();
5593 if(this.hideTrigger){
5594 this.trigger.setDisplayed(false);
5596 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
5600 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
5603 //this.trigger.addClassOnOver('x-form-trigger-over');
5604 //this.trigger.addClassOnClick('x-form-trigger-click');
5607 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
5612 initTrigger : function(){
5617 onDestroy : function(){
5619 this.trigger.removeAllListeners();
5620 // this.trigger.remove();
5623 // this.wrap.remove();
5625 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
5629 onFocus : function(){
5630 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
5633 this.wrap.addClass('x-trigger-wrap-focus');
5634 this.mimicing = true;
5635 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
5636 if(this.monitorTab){
5637 this.el.on("keydown", this.checkTab, this);
5644 checkTab : function(e){
5645 if(e.getKey() == e.TAB){
5651 onBlur : function(){
5656 mimicBlur : function(e, t){
5658 if(!this.wrap.contains(t) && this.validateBlur()){
5665 triggerBlur : function(){
5666 this.mimicing = false;
5667 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
5668 if(this.monitorTab){
5669 this.el.un("keydown", this.checkTab, this);
5671 //this.wrap.removeClass('x-trigger-wrap-focus');
5672 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
5676 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
5677 validateBlur : function(e, t){
5682 onDisable : function(){
5683 Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
5685 // this.wrap.addClass('x-item-disabled');
5690 onEnable : function(){
5691 Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
5693 // this.el.removeClass('x-item-disabled');
5698 onShow : function(){
5699 var ae = this.getActionEl();
5702 ae.dom.style.display = '';
5703 ae.dom.style.visibility = 'visible';
5709 onHide : function(){
5710 var ae = this.getActionEl();
5711 ae.dom.style.display = 'none';
5715 * The function that should handle the trigger's click event. This method does nothing by default until overridden
5716 * by an implementing function.
5718 * @param {EventObject} e
5720 onTriggerClick : Roo.emptyFn
5724 * Ext JS Library 1.1.1
5725 * Copyright(c) 2006-2007, Ext JS, LLC.
5727 * Originally Released Under LGPL - original licence link has changed is not relivant.
5730 * <script type="text/javascript">
5735 * @class Roo.data.SortTypes
5737 * Defines the default sorting (casting?) comparison functions used when sorting data.
5739 Roo.data.SortTypes = {
5741 * Default sort that does nothing
5742 * @param {Mixed} s The value being converted
5743 * @return {Mixed} The comparison value
5750 * The regular expression used to strip tags
5754 stripTagsRE : /<\/?[^>]+>/gi,
5757 * Strips all HTML tags to sort on text only
5758 * @param {Mixed} s The value being converted
5759 * @return {String} The comparison value
5761 asText : function(s){
5762 return String(s).replace(this.stripTagsRE, "");
5766 * Strips all HTML tags to sort on text only - Case insensitive
5767 * @param {Mixed} s The value being converted
5768 * @return {String} The comparison value
5770 asUCText : function(s){
5771 return String(s).toUpperCase().replace(this.stripTagsRE, "");
5775 * Case insensitive string
5776 * @param {Mixed} s The value being converted
5777 * @return {String} The comparison value
5779 asUCString : function(s) {
5780 return String(s).toUpperCase();
5785 * @param {Mixed} s The value being converted
5786 * @return {Number} The comparison value
5788 asDate : function(s) {
5792 if(s instanceof Date){
5795 return Date.parse(String(s));
5800 * @param {Mixed} s The value being converted
5801 * @return {Float} The comparison value
5803 asFloat : function(s) {
5804 var val = parseFloat(String(s).replace(/,/g, ""));
5805 if(isNaN(val)) val = 0;
5811 * @param {Mixed} s The value being converted
5812 * @return {Number} The comparison value
5814 asInt : function(s) {
5815 var val = parseInt(String(s).replace(/,/g, ""));
5816 if(isNaN(val)) val = 0;
5821 * Ext JS Library 1.1.1
5822 * Copyright(c) 2006-2007, Ext JS, LLC.
5824 * Originally Released Under LGPL - original licence link has changed is not relivant.
5827 * <script type="text/javascript">
5831 * @class Roo.data.Record
5832 * Instances of this class encapsulate both record <em>definition</em> information, and record
5833 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
5834 * to access Records cached in an {@link Roo.data.Store} object.<br>
5836 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
5837 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
5840 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
5842 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
5843 * {@link #create}. The parameters are the same.
5844 * @param {Array} data An associative Array of data values keyed by the field name.
5845 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
5846 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
5847 * not specified an integer id is generated.
5849 Roo.data.Record = function(data, id){
5850 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
5855 * Generate a constructor for a specific record layout.
5856 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
5857 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
5858 * Each field definition object may contain the following properties: <ul>
5859 * <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,
5860 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
5861 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
5862 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
5863 * is being used, then this is a string containing the javascript expression to reference the data relative to
5864 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
5865 * to the data item relative to the record element. If the mapping expression is the same as the field name,
5866 * this may be omitted.</p></li>
5867 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
5868 * <ul><li>auto (Default, implies no conversion)</li>
5873 * <li>date</li></ul></p></li>
5874 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
5875 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
5876 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
5877 * by the Reader into an object that will be stored in the Record. It is passed the
5878 * following parameters:<ul>
5879 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
5881 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
5883 * <br>usage:<br><pre><code>
5884 var TopicRecord = Roo.data.Record.create(
5885 {name: 'title', mapping: 'topic_title'},
5886 {name: 'author', mapping: 'username'},
5887 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
5888 {name: 'lastPost', mapping: 'post_time', type: 'date'},
5889 {name: 'lastPoster', mapping: 'user2'},
5890 {name: 'excerpt', mapping: 'post_text'}
5893 var myNewRecord = new TopicRecord({
5894 title: 'Do my job please',
5897 lastPost: new Date(),
5898 lastPoster: 'Animal',
5899 excerpt: 'No way dude!'
5901 myStore.add(myNewRecord);
5906 Roo.data.Record.create = function(o){
5908 f.superclass.constructor.apply(this, arguments);
5910 Roo.extend(f, Roo.data.Record);
5911 var p = f.prototype;
5912 p.fields = new Roo.util.MixedCollection(false, function(field){
5915 for(var i = 0, len = o.length; i < len; i++){
5916 p.fields.add(new Roo.data.Field(o[i]));
5918 f.getField = function(name){
5919 return p.fields.get(name);
5924 Roo.data.Record.AUTO_ID = 1000;
5925 Roo.data.Record.EDIT = 'edit';
5926 Roo.data.Record.REJECT = 'reject';
5927 Roo.data.Record.COMMIT = 'commit';
5929 Roo.data.Record.prototype = {
5931 * Readonly flag - true if this record has been modified.
5940 join : function(store){
5945 * Set the named field to the specified value.
5946 * @param {String} name The name of the field to set.
5947 * @param {Object} value The value to set the field to.
5949 set : function(name, value){
5950 if(this.data[name] == value){
5957 if(typeof this.modified[name] == 'undefined'){
5958 this.modified[name] = this.data[name];
5960 this.data[name] = value;
5961 if(!this.editing && this.store){
5962 this.store.afterEdit(this);
5967 * Get the value of the named field.
5968 * @param {String} name The name of the field to get the value of.
5969 * @return {Object} The value of the field.
5971 get : function(name){
5972 return this.data[name];
5976 beginEdit : function(){
5977 this.editing = true;
5982 cancelEdit : function(){
5983 this.editing = false;
5984 delete this.modified;
5988 endEdit : function(){
5989 this.editing = false;
5990 if(this.dirty && this.store){
5991 this.store.afterEdit(this);
5996 * Usually called by the {@link Roo.data.Store} which owns the Record.
5997 * Rejects all changes made to the Record since either creation, or the last commit operation.
5998 * Modified fields are reverted to their original values.
6000 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
6001 * of reject operations.
6003 reject : function(){
6004 var m = this.modified;
6006 if(typeof m[n] != "function"){
6007 this.data[n] = m[n];
6011 delete this.modified;
6012 this.editing = false;
6014 this.store.afterReject(this);
6019 * Usually called by the {@link Roo.data.Store} which owns the Record.
6020 * Commits all changes made to the Record since either creation, or the last commit operation.
6022 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
6023 * of commit operations.
6025 commit : function(){
6027 delete this.modified;
6028 this.editing = false;
6030 this.store.afterCommit(this);
6035 hasError : function(){
6036 return this.error != null;
6040 clearError : function(){
6045 * Creates a copy of this record.
6046 * @param {String} id (optional) A new record id if you don't want to use this record's id
6049 copy : function(newId) {
6050 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
6054 * Ext JS Library 1.1.1
6055 * Copyright(c) 2006-2007, Ext JS, LLC.
6057 * Originally Released Under LGPL - original licence link has changed is not relivant.
6060 * <script type="text/javascript">
6066 * @class Roo.data.Store
6067 * @extends Roo.util.Observable
6068 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
6069 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
6071 * 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
6072 * has no knowledge of the format of the data returned by the Proxy.<br>
6074 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
6075 * instances from the data object. These records are cached and made available through accessor functions.
6077 * Creates a new Store.
6078 * @param {Object} config A config object containing the objects needed for the Store to access data,
6079 * and read the data into Records.
6081 Roo.data.Store = function(config){
6082 this.data = new Roo.util.MixedCollection(false);
6083 this.data.getKey = function(o){
6086 this.baseParams = {};
6093 "multisort" : "_multisort"
6096 if(config && config.data){
6097 this.inlineData = config.data;
6101 Roo.apply(this, config);
6103 if(this.reader){ // reader passed
6104 this.reader = Roo.factory(this.reader, Roo.data);
6105 this.reader.xmodule = this.xmodule || false;
6106 if(!this.recordType){
6107 this.recordType = this.reader.recordType;
6109 if(this.reader.onMetaChange){
6110 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
6114 if(this.recordType){
6115 this.fields = this.recordType.prototype.fields;
6121 * @event datachanged
6122 * Fires when the data cache has changed, and a widget which is using this Store
6123 * as a Record cache should refresh its view.
6124 * @param {Store} this
6129 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
6130 * @param {Store} this
6131 * @param {Object} meta The JSON metadata
6136 * Fires when Records have been added to the Store
6137 * @param {Store} this
6138 * @param {Roo.data.Record[]} records The array of Records added
6139 * @param {Number} index The index at which the record(s) were added
6144 * Fires when a Record has been removed from the Store
6145 * @param {Store} this
6146 * @param {Roo.data.Record} record The Record that was removed
6147 * @param {Number} index The index at which the record was removed
6152 * Fires when a Record has been updated
6153 * @param {Store} this
6154 * @param {Roo.data.Record} record The Record that was updated
6155 * @param {String} operation The update operation being performed. Value may be one of:
6157 Roo.data.Record.EDIT
6158 Roo.data.Record.REJECT
6159 Roo.data.Record.COMMIT
6165 * Fires when the data cache has been cleared.
6166 * @param {Store} this
6171 * Fires before a request is made for a new data object. If the beforeload handler returns false
6172 * the load action will be canceled.
6173 * @param {Store} this
6174 * @param {Object} options The loading options that were specified (see {@link #load} for details)
6178 * @event beforeloadadd
6179 * Fires after a new set of Records has been loaded.
6180 * @param {Store} this
6181 * @param {Roo.data.Record[]} records The Records that were loaded
6182 * @param {Object} options The loading options that were specified (see {@link #load} for details)
6184 beforeloadadd : true,
6187 * Fires after a new set of Records has been loaded, before they are added to the store.
6188 * @param {Store} this
6189 * @param {Roo.data.Record[]} records The Records that were loaded
6190 * @param {Object} options The loading options that were specified (see {@link #load} for details)
6191 * @params {Object} return from reader
6195 * @event loadexception
6196 * Fires if an exception occurs in the Proxy during loading.
6197 * Called with the signature of the Proxy's "loadexception" event.
6198 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
6201 * @param {Object} return from JsonData.reader() - success, totalRecords, records
6202 * @param {Object} load options
6203 * @param {Object} jsonData from your request (normally this contains the Exception)
6205 loadexception : true
6209 this.proxy = Roo.factory(this.proxy, Roo.data);
6210 this.proxy.xmodule = this.xmodule || false;
6211 this.relayEvents(this.proxy, ["loadexception"]);
6213 this.sortToggle = {};
6214 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
6216 Roo.data.Store.superclass.constructor.call(this);
6218 if(this.inlineData){
6219 this.loadData(this.inlineData);
6220 delete this.inlineData;
6224 Roo.extend(Roo.data.Store, Roo.util.Observable, {
6226 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
6227 * without a remote query - used by combo/forms at present.
6231 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
6234 * @cfg {Array} data Inline data to be loaded when the store is initialized.
6237 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
6238 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
6241 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
6242 * on any HTTP request
6245 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
6248 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
6252 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
6253 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
6258 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
6259 * loaded or when a record is removed. (defaults to false).
6261 pruneModifiedRecords : false,
6267 * Add Records to the Store and fires the add event.
6268 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
6270 add : function(records){
6271 records = [].concat(records);
6272 for(var i = 0, len = records.length; i < len; i++){
6273 records[i].join(this);
6275 var index = this.data.length;
6276 this.data.addAll(records);
6277 this.fireEvent("add", this, records, index);
6281 * Remove a Record from the Store and fires the remove event.
6282 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
6284 remove : function(record){
6285 var index = this.data.indexOf(record);
6286 this.data.removeAt(index);
6287 if(this.pruneModifiedRecords){
6288 this.modified.remove(record);
6290 this.fireEvent("remove", this, record, index);
6294 * Remove all Records from the Store and fires the clear event.
6296 removeAll : function(){
6298 if(this.pruneModifiedRecords){
6301 this.fireEvent("clear", this);
6305 * Inserts Records to the Store at the given index and fires the add event.
6306 * @param {Number} index The start index at which to insert the passed Records.
6307 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
6309 insert : function(index, records){
6310 records = [].concat(records);
6311 for(var i = 0, len = records.length; i < len; i++){
6312 this.data.insert(index, records[i]);
6313 records[i].join(this);
6315 this.fireEvent("add", this, records, index);
6319 * Get the index within the cache of the passed Record.
6320 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
6321 * @return {Number} The index of the passed Record. Returns -1 if not found.
6323 indexOf : function(record){
6324 return this.data.indexOf(record);
6328 * Get the index within the cache of the Record with the passed id.
6329 * @param {String} id The id of the Record to find.
6330 * @return {Number} The index of the Record. Returns -1 if not found.
6332 indexOfId : function(id){
6333 return this.data.indexOfKey(id);
6337 * Get the Record with the specified id.
6338 * @param {String} id The id of the Record to find.
6339 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
6341 getById : function(id){
6342 return this.data.key(id);
6346 * Get the Record at the specified index.
6347 * @param {Number} index The index of the Record to find.
6348 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
6350 getAt : function(index){
6351 return this.data.itemAt(index);
6355 * Returns a range of Records between specified indices.
6356 * @param {Number} startIndex (optional) The starting index (defaults to 0)
6357 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
6358 * @return {Roo.data.Record[]} An array of Records
6360 getRange : function(start, end){
6361 return this.data.getRange(start, end);
6365 storeOptions : function(o){
6366 o = Roo.apply({}, o);
6369 this.lastOptions = o;
6373 * Loads the Record cache from the configured Proxy using the configured Reader.
6375 * If using remote paging, then the first load call must specify the <em>start</em>
6376 * and <em>limit</em> properties in the options.params property to establish the initial
6377 * position within the dataset, and the number of Records to cache on each read from the Proxy.
6379 * <strong>It is important to note that for remote data sources, loading is asynchronous,
6380 * and this call will return before the new data has been loaded. Perform any post-processing
6381 * in a callback function, or in a "load" event handler.</strong>
6383 * @param {Object} options An object containing properties which control loading options:<ul>
6384 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
6385 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
6386 * passed the following arguments:<ul>
6387 * <li>r : Roo.data.Record[]</li>
6388 * <li>options: Options object from the load call</li>
6389 * <li>success: Boolean success indicator</li></ul></li>
6390 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
6391 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
6394 load : function(options){
6395 options = options || {};
6396 if(this.fireEvent("beforeload", this, options) !== false){
6397 this.storeOptions(options);
6398 var p = Roo.apply(options.params || {}, this.baseParams);
6399 // if meta was not loaded from remote source.. try requesting it.
6400 if (!this.reader.metaFromRemote) {
6403 if(this.sortInfo && this.remoteSort){
6404 var pn = this.paramNames;
6405 p[pn["sort"]] = this.sortInfo.field;
6406 p[pn["dir"]] = this.sortInfo.direction;
6408 if (this.multiSort) {
6409 var pn = this.paramNames;
6410 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
6413 this.proxy.load(p, this.reader, this.loadRecords, this, options);
6418 * Reloads the Record cache from the configured Proxy using the configured Reader and
6419 * the options from the last load operation performed.
6420 * @param {Object} options (optional) An object containing properties which may override the options
6421 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
6422 * the most recently used options are reused).
6424 reload : function(options){
6425 this.load(Roo.applyIf(options||{}, this.lastOptions));
6429 // Called as a callback by the Reader during a load operation.
6430 loadRecords : function(o, options, success){
6431 if(!o || success === false){
6432 if(success !== false){
6433 this.fireEvent("load", this, [], options, o);
6435 if(options.callback){
6436 options.callback.call(options.scope || this, [], options, false);
6440 // if data returned failure - throw an exception.
6441 if (o.success === false) {
6442 // show a message if no listener is registered.
6443 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
6444 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
6446 // loadmask wil be hooked into this..
6447 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
6450 var r = o.records, t = o.totalRecords || r.length;
6452 this.fireEvent("beforeloadadd", this, r, options, o);
6454 if(!options || options.add !== true){
6455 if(this.pruneModifiedRecords){
6458 for(var i = 0, len = r.length; i < len; i++){
6462 this.data = this.snapshot;
6463 delete this.snapshot;
6466 this.data.addAll(r);
6467 this.totalLength = t;
6469 this.fireEvent("datachanged", this);
6471 this.totalLength = Math.max(t, this.data.length+r.length);
6474 this.fireEvent("load", this, r, options, o);
6475 if(options.callback){
6476 options.callback.call(options.scope || this, r, options, true);
6482 * Loads data from a passed data block. A Reader which understands the format of the data
6483 * must have been configured in the constructor.
6484 * @param {Object} data The data block from which to read the Records. The format of the data expected
6485 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
6486 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
6488 loadData : function(o, append){
6489 var r = this.reader.readRecords(o);
6490 this.loadRecords(r, {add: append}, true);
6494 * Gets the number of cached records.
6496 * <em>If using paging, this may not be the total size of the dataset. If the data object
6497 * used by the Reader contains the dataset size, then the getTotalCount() function returns
6498 * the data set size</em>
6500 getCount : function(){
6501 return this.data.length || 0;
6505 * Gets the total number of records in the dataset as returned by the server.
6507 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
6508 * the dataset size</em>
6510 getTotalCount : function(){
6511 return this.totalLength || 0;
6515 * Returns the sort state of the Store as an object with two properties:
6517 field {String} The name of the field by which the Records are sorted
6518 direction {String} The sort order, "ASC" or "DESC"
6521 getSortState : function(){
6522 return this.sortInfo;
6526 applySort : function(){
6527 if(this.sortInfo && !this.remoteSort){
6528 var s = this.sortInfo, f = s.field;
6529 var st = this.fields.get(f).sortType;
6530 var fn = function(r1, r2){
6531 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
6532 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
6534 this.data.sort(s.direction, fn);
6535 if(this.snapshot && this.snapshot != this.data){
6536 this.snapshot.sort(s.direction, fn);
6542 * Sets the default sort column and order to be used by the next load operation.
6543 * @param {String} fieldName The name of the field to sort by.
6544 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
6546 setDefaultSort : function(field, dir){
6547 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
6552 * If remote sorting is used, the sort is performed on the server, and the cache is
6553 * reloaded. If local sorting is used, the cache is sorted internally.
6554 * @param {String} fieldName The name of the field to sort by.
6555 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
6557 sort : function(fieldName, dir){
6558 var f = this.fields.get(fieldName);
6560 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
6562 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
6563 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
6568 this.sortToggle[f.name] = dir;
6569 this.sortInfo = {field: f.name, direction: dir};
6570 if(!this.remoteSort){
6572 this.fireEvent("datachanged", this);
6574 this.load(this.lastOptions);
6579 * Calls the specified function for each of the Records in the cache.
6580 * @param {Function} fn The function to call. The Record is passed as the first parameter.
6581 * Returning <em>false</em> aborts and exits the iteration.
6582 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
6584 each : function(fn, scope){
6585 this.data.each(fn, scope);
6589 * Gets all records modified since the last commit. Modified records are persisted across load operations
6590 * (e.g., during paging).
6591 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
6593 getModifiedRecords : function(){
6594 return this.modified;
6598 createFilterFn : function(property, value, anyMatch){
6599 if(!value.exec){ // not a regex
6600 value = String(value);
6601 if(value.length == 0){
6604 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
6607 return value.test(r.data[property]);
6612 * Sums the value of <i>property</i> for each record between start and end and returns the result.
6613 * @param {String} property A field on your records
6614 * @param {Number} start The record index to start at (defaults to 0)
6615 * @param {Number} end The last record index to include (defaults to length - 1)
6616 * @return {Number} The sum
6618 sum : function(property, start, end){
6619 var rs = this.data.items, v = 0;
6621 end = (end || end === 0) ? end : rs.length-1;
6623 for(var i = start; i <= end; i++){
6624 v += (rs[i].data[property] || 0);
6630 * Filter the records by a specified property.
6631 * @param {String} field A field on your records
6632 * @param {String/RegExp} value Either a string that the field
6633 * should start with or a RegExp to test against the field
6634 * @param {Boolean} anyMatch True to match any part not just the beginning
6636 filter : function(property, value, anyMatch){
6637 var fn = this.createFilterFn(property, value, anyMatch);
6638 return fn ? this.filterBy(fn) : this.clearFilter();
6642 * Filter by a function. The specified function will be called with each
6643 * record in this data source. If the function returns true the record is included,
6644 * otherwise it is filtered.
6645 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
6646 * @param {Object} scope (optional) The scope of the function (defaults to this)
6648 filterBy : function(fn, scope){
6649 this.snapshot = this.snapshot || this.data;
6650 this.data = this.queryBy(fn, scope||this);
6651 this.fireEvent("datachanged", this);
6655 * Query the records by a specified property.
6656 * @param {String} field A field on your records
6657 * @param {String/RegExp} value Either a string that the field
6658 * should start with or a RegExp to test against the field
6659 * @param {Boolean} anyMatch True to match any part not just the beginning
6660 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
6662 query : function(property, value, anyMatch){
6663 var fn = this.createFilterFn(property, value, anyMatch);
6664 return fn ? this.queryBy(fn) : this.data.clone();
6668 * Query by a function. The specified function will be called with each
6669 * record in this data source. If the function returns true the record is included
6671 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
6672 * @param {Object} scope (optional) The scope of the function (defaults to this)
6673 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
6675 queryBy : function(fn, scope){
6676 var data = this.snapshot || this.data;
6677 return data.filterBy(fn, scope||this);
6681 * Collects unique values for a particular dataIndex from this store.
6682 * @param {String} dataIndex The property to collect
6683 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
6684 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
6685 * @return {Array} An array of the unique values
6687 collect : function(dataIndex, allowNull, bypassFilter){
6688 var d = (bypassFilter === true && this.snapshot) ?
6689 this.snapshot.items : this.data.items;
6690 var v, sv, r = [], l = {};
6691 for(var i = 0, len = d.length; i < len; i++){
6692 v = d[i].data[dataIndex];
6694 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
6703 * Revert to a view of the Record cache with no filtering applied.
6704 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
6706 clearFilter : function(suppressEvent){
6707 if(this.snapshot && this.snapshot != this.data){
6708 this.data = this.snapshot;
6709 delete this.snapshot;
6710 if(suppressEvent !== true){
6711 this.fireEvent("datachanged", this);
6717 afterEdit : function(record){
6718 if(this.modified.indexOf(record) == -1){
6719 this.modified.push(record);
6721 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
6725 afterReject : function(record){
6726 this.modified.remove(record);
6727 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
6731 afterCommit : function(record){
6732 this.modified.remove(record);
6733 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
6737 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
6738 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
6740 commitChanges : function(){
6741 var m = this.modified.slice(0);
6743 for(var i = 0, len = m.length; i < len; i++){
6749 * Cancel outstanding changes on all changed records.
6751 rejectChanges : function(){
6752 var m = this.modified.slice(0);
6754 for(var i = 0, len = m.length; i < len; i++){
6759 onMetaChange : function(meta, rtype, o){
6760 this.recordType = rtype;
6761 this.fields = rtype.prototype.fields;
6762 delete this.snapshot;
6763 this.sortInfo = meta.sortInfo || this.sortInfo;
6765 this.fireEvent('metachange', this, this.reader.meta);
6768 moveIndex : function(data, type)
6770 var index = this.indexOf(data);
6772 var newIndex = index + type;
6776 this.insert(newIndex, data);
6781 * Ext JS Library 1.1.1
6782 * Copyright(c) 2006-2007, Ext JS, LLC.
6784 * Originally Released Under LGPL - original licence link has changed is not relivant.
6787 * <script type="text/javascript">
6791 * @class Roo.data.SimpleStore
6792 * @extends Roo.data.Store
6793 * Small helper class to make creating Stores from Array data easier.
6794 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
6795 * @cfg {Array} fields An array of field definition objects, or field name strings.
6796 * @cfg {Array} data The multi-dimensional array of data
6798 * @param {Object} config
6800 Roo.data.SimpleStore = function(config){
6801 Roo.data.SimpleStore.superclass.constructor.call(this, {
6803 reader: new Roo.data.ArrayReader({
6806 Roo.data.Record.create(config.fields)
6808 proxy : new Roo.data.MemoryProxy(config.data)
6812 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
6814 * Ext JS Library 1.1.1
6815 * Copyright(c) 2006-2007, Ext JS, LLC.
6817 * Originally Released Under LGPL - original licence link has changed is not relivant.
6820 * <script type="text/javascript">
6825 * @extends Roo.data.Store
6826 * @class Roo.data.JsonStore
6827 * Small helper class to make creating Stores for JSON data easier. <br/>
6829 var store = new Roo.data.JsonStore({
6830 url: 'get-images.php',
6832 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
6835 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
6836 * JsonReader and HttpProxy (unless inline data is provided).</b>
6837 * @cfg {Array} fields An array of field definition objects, or field name strings.
6839 * @param {Object} config
6841 Roo.data.JsonStore = function(c){
6842 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
6843 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
6844 reader: new Roo.data.JsonReader(c, c.fields)
6847 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
6849 * Ext JS Library 1.1.1
6850 * Copyright(c) 2006-2007, Ext JS, LLC.
6852 * Originally Released Under LGPL - original licence link has changed is not relivant.
6855 * <script type="text/javascript">
6859 Roo.data.Field = function(config){
6860 if(typeof config == "string"){
6861 config = {name: config};
6863 Roo.apply(this, config);
6869 var st = Roo.data.SortTypes;
6870 // named sortTypes are supported, here we look them up
6871 if(typeof this.sortType == "string"){
6872 this.sortType = st[this.sortType];
6875 // set default sortType for strings and dates
6879 this.sortType = st.asUCString;
6882 this.sortType = st.asDate;
6885 this.sortType = st.none;
6890 var stripRe = /[\$,%]/g;
6892 // prebuilt conversion function for this field, instead of
6893 // switching every time we're reading a value
6895 var cv, dateFormat = this.dateFormat;
6900 cv = function(v){ return v; };
6903 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
6907 return v !== undefined && v !== null && v !== '' ?
6908 parseInt(String(v).replace(stripRe, ""), 10) : '';
6913 return v !== undefined && v !== null && v !== '' ?
6914 parseFloat(String(v).replace(stripRe, ""), 10) : '';
6919 cv = function(v){ return v === true || v === "true" || v == 1; };
6926 if(v instanceof Date){
6930 if(dateFormat == "timestamp"){
6931 return new Date(v*1000);
6933 return Date.parseDate(v, dateFormat);
6935 var parsed = Date.parse(v);
6936 return parsed ? new Date(parsed) : null;
6945 Roo.data.Field.prototype = {
6953 * Ext JS Library 1.1.1
6954 * Copyright(c) 2006-2007, Ext JS, LLC.
6956 * Originally Released Under LGPL - original licence link has changed is not relivant.
6959 * <script type="text/javascript">
6962 // Base class for reading structured data from a data source. This class is intended to be
6963 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
6966 * @class Roo.data.DataReader
6967 * Base class for reading structured data from a data source. This class is intended to be
6968 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
6971 Roo.data.DataReader = function(meta, recordType){
6975 this.recordType = recordType instanceof Array ?
6976 Roo.data.Record.create(recordType) : recordType;
6979 Roo.data.DataReader.prototype = {
6981 * Create an empty record
6982 * @param {Object} data (optional) - overlay some values
6983 * @return {Roo.data.Record} record created.
6985 newRow : function(d) {
6987 this.recordType.prototype.fields.each(function(c) {
6989 case 'int' : da[c.name] = 0; break;
6990 case 'date' : da[c.name] = new Date(); break;
6991 case 'float' : da[c.name] = 0.0; break;
6992 case 'boolean' : da[c.name] = false; break;
6993 default : da[c.name] = ""; break;
6997 return new this.recordType(Roo.apply(da, d));
7002 * Ext JS Library 1.1.1
7003 * Copyright(c) 2006-2007, Ext JS, LLC.
7005 * Originally Released Under LGPL - original licence link has changed is not relivant.
7008 * <script type="text/javascript">
7012 * @class Roo.data.DataProxy
7013 * @extends Roo.data.Observable
7014 * This class is an abstract base class for implementations which provide retrieval of
7015 * unformatted data objects.<br>
7017 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
7018 * (of the appropriate type which knows how to parse the data object) to provide a block of
7019 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
7021 * Custom implementations must implement the load method as described in
7022 * {@link Roo.data.HttpProxy#load}.
7024 Roo.data.DataProxy = function(){
7028 * Fires before a network request is made to retrieve a data object.
7029 * @param {Object} This DataProxy object.
7030 * @param {Object} params The params parameter to the load function.
7035 * Fires before the load method's callback is called.
7036 * @param {Object} This DataProxy object.
7037 * @param {Object} o The data object.
7038 * @param {Object} arg The callback argument object passed to the load function.
7042 * @event loadexception
7043 * Fires if an Exception occurs during data retrieval.
7044 * @param {Object} This DataProxy object.
7045 * @param {Object} o The data object.
7046 * @param {Object} arg The callback argument object passed to the load function.
7047 * @param {Object} e The Exception.
7049 loadexception : true
7051 Roo.data.DataProxy.superclass.constructor.call(this);
7054 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
7057 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
7061 * Ext JS Library 1.1.1
7062 * Copyright(c) 2006-2007, Ext JS, LLC.
7064 * Originally Released Under LGPL - original licence link has changed is not relivant.
7067 * <script type="text/javascript">
7070 * @class Roo.data.MemoryProxy
7071 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
7072 * to the Reader when its load method is called.
7074 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
7076 Roo.data.MemoryProxy = function(data){
7080 Roo.data.MemoryProxy.superclass.constructor.call(this);
7084 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
7086 * Load data from the requested source (in this case an in-memory
7087 * data object passed to the constructor), read the data object into
7088 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
7089 * process that block using the passed callback.
7090 * @param {Object} params This parameter is not used by the MemoryProxy class.
7091 * @param {Roo.data.DataReader} reader The Reader object which converts the data
7092 * object into a block of Roo.data.Records.
7093 * @param {Function} callback The function into which to pass the block of Roo.data.records.
7094 * The function must be passed <ul>
7095 * <li>The Record block object</li>
7096 * <li>The "arg" argument from the load function</li>
7097 * <li>A boolean success indicator</li>
7099 * @param {Object} scope The scope in which to call the callback
7100 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
7102 load : function(params, reader, callback, scope, arg){
7103 params = params || {};
7106 result = reader.readRecords(this.data);
7108 this.fireEvent("loadexception", this, arg, null, e);
7109 callback.call(scope, null, arg, false);
7112 callback.call(scope, result, arg, true);
7116 update : function(params, records){
7121 * Ext JS Library 1.1.1
7122 * Copyright(c) 2006-2007, Ext JS, LLC.
7124 * Originally Released Under LGPL - original licence link has changed is not relivant.
7127 * <script type="text/javascript">
7130 * @class Roo.data.HttpProxy
7131 * @extends Roo.data.DataProxy
7132 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
7133 * configured to reference a certain URL.<br><br>
7135 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
7136 * from which the running page was served.<br><br>
7138 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
7140 * Be aware that to enable the browser to parse an XML document, the server must set
7141 * the Content-Type header in the HTTP response to "text/xml".
7143 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
7144 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
7145 * will be used to make the request.
7147 Roo.data.HttpProxy = function(conn){
7148 Roo.data.HttpProxy.superclass.constructor.call(this);
7149 // is conn a conn config or a real conn?
7151 this.useAjax = !conn || !conn.events;
7155 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
7156 // thse are take from connection...
7159 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
7162 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
7163 * extra parameters to each request made by this object. (defaults to undefined)
7166 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
7167 * to each request made by this object. (defaults to undefined)
7170 * @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)
7173 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
7176 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
7182 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
7186 * Return the {@link Roo.data.Connection} object being used by this Proxy.
7187 * @return {Connection} The Connection object. This object may be used to subscribe to events on
7188 * a finer-grained basis than the DataProxy events.
7190 getConnection : function(){
7191 return this.useAjax ? Roo.Ajax : this.conn;
7195 * Load data from the configured {@link Roo.data.Connection}, read the data object into
7196 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
7197 * process that block using the passed callback.
7198 * @param {Object} params An object containing properties which are to be used as HTTP parameters
7199 * for the request to the remote server.
7200 * @param {Roo.data.DataReader} reader The Reader object which converts the data
7201 * object into a block of Roo.data.Records.
7202 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
7203 * The function must be passed <ul>
7204 * <li>The Record block object</li>
7205 * <li>The "arg" argument from the load function</li>
7206 * <li>A boolean success indicator</li>
7208 * @param {Object} scope The scope in which to call the callback
7209 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
7211 load : function(params, reader, callback, scope, arg){
7212 if(this.fireEvent("beforeload", this, params) !== false){
7214 params : params || {},
7216 callback : callback,
7221 callback : this.loadResponse,
7225 Roo.applyIf(o, this.conn);
7226 if(this.activeRequest){
7227 Roo.Ajax.abort(this.activeRequest);
7229 this.activeRequest = Roo.Ajax.request(o);
7231 this.conn.request(o);
7234 callback.call(scope||this, null, arg, false);
7239 loadResponse : function(o, success, response){
7240 delete this.activeRequest;
7242 this.fireEvent("loadexception", this, o, response);
7243 o.request.callback.call(o.request.scope, null, o.request.arg, false);
7248 result = o.reader.read(response);
7250 this.fireEvent("loadexception", this, o, response, e);
7251 o.request.callback.call(o.request.scope, null, o.request.arg, false);
7255 this.fireEvent("load", this, o, o.request.arg);
7256 o.request.callback.call(o.request.scope, result, o.request.arg, true);
7260 update : function(dataSet){
7265 updateResponse : function(dataSet){
7270 * Ext JS Library 1.1.1
7271 * Copyright(c) 2006-2007, Ext JS, LLC.
7273 * Originally Released Under LGPL - original licence link has changed is not relivant.
7276 * <script type="text/javascript">
7280 * @class Roo.data.ScriptTagProxy
7281 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
7282 * other than the originating domain of the running page.<br><br>
7284 * <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
7285 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
7287 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
7288 * source code that is used as the source inside a <script> tag.<br><br>
7290 * In order for the browser to process the returned data, the server must wrap the data object
7291 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
7292 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
7293 * depending on whether the callback name was passed:
7296 boolean scriptTag = false;
7297 String cb = request.getParameter("callback");
7300 response.setContentType("text/javascript");
7302 response.setContentType("application/x-json");
7304 Writer out = response.getWriter();
7306 out.write(cb + "(");
7308 out.print(dataBlock.toJsonString());
7315 * @param {Object} config A configuration object.
7317 Roo.data.ScriptTagProxy = function(config){
7318 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
7319 Roo.apply(this, config);
7320 this.head = document.getElementsByTagName("head")[0];
7323 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
7325 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
7327 * @cfg {String} url The URL from which to request the data object.
7330 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
7334 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
7335 * the server the name of the callback function set up by the load call to process the returned data object.
7336 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
7337 * javascript output which calls this named function passing the data object as its only parameter.
7339 callbackParam : "callback",
7341 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
7342 * name to the request.
7347 * Load data from the configured URL, read the data object into
7348 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
7349 * process that block using the passed callback.
7350 * @param {Object} params An object containing properties which are to be used as HTTP parameters
7351 * for the request to the remote server.
7352 * @param {Roo.data.DataReader} reader The Reader object which converts the data
7353 * object into a block of Roo.data.Records.
7354 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
7355 * The function must be passed <ul>
7356 * <li>The Record block object</li>
7357 * <li>The "arg" argument from the load function</li>
7358 * <li>A boolean success indicator</li>
7360 * @param {Object} scope The scope in which to call the callback
7361 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
7363 load : function(params, reader, callback, scope, arg){
7364 if(this.fireEvent("beforeload", this, params) !== false){
7366 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
7369 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
7371 url += "&_dc=" + (new Date().getTime());
7373 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
7376 cb : "stcCallback"+transId,
7377 scriptId : "stcScript"+transId,
7381 callback : callback,
7387 window[trans.cb] = function(o){
7388 conn.handleResponse(o, trans);
7391 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
7393 if(this.autoAbort !== false){
7397 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
7399 var script = document.createElement("script");
7400 script.setAttribute("src", url);
7401 script.setAttribute("type", "text/javascript");
7402 script.setAttribute("id", trans.scriptId);
7403 this.head.appendChild(script);
7407 callback.call(scope||this, null, arg, false);
7412 isLoading : function(){
7413 return this.trans ? true : false;
7417 * Abort the current server request.
7420 if(this.isLoading()){
7421 this.destroyTrans(this.trans);
7426 destroyTrans : function(trans, isLoaded){
7427 this.head.removeChild(document.getElementById(trans.scriptId));
7428 clearTimeout(trans.timeoutId);
7430 window[trans.cb] = undefined;
7432 delete window[trans.cb];
7435 // if hasn't been loaded, wait for load to remove it to prevent script error
7436 window[trans.cb] = function(){
7437 window[trans.cb] = undefined;
7439 delete window[trans.cb];
7446 handleResponse : function(o, trans){
7448 this.destroyTrans(trans, true);
7451 result = trans.reader.readRecords(o);
7453 this.fireEvent("loadexception", this, o, trans.arg, e);
7454 trans.callback.call(trans.scope||window, null, trans.arg, false);
7457 this.fireEvent("load", this, o, trans.arg);
7458 trans.callback.call(trans.scope||window, result, trans.arg, true);
7462 handleFailure : function(trans){
7464 this.destroyTrans(trans, false);
7465 this.fireEvent("loadexception", this, null, trans.arg);
7466 trans.callback.call(trans.scope||window, null, trans.arg, false);
7470 * Ext JS Library 1.1.1
7471 * Copyright(c) 2006-2007, Ext JS, LLC.
7473 * Originally Released Under LGPL - original licence link has changed is not relivant.
7476 * <script type="text/javascript">
7480 * @class Roo.data.JsonReader
7481 * @extends Roo.data.DataReader
7482 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
7483 * based on mappings in a provided Roo.data.Record constructor.
7485 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
7486 * in the reply previously.
7491 var RecordDef = Roo.data.Record.create([
7492 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
7493 {name: 'occupation'} // This field will use "occupation" as the mapping.
7495 var myReader = new Roo.data.JsonReader({
7496 totalProperty: "results", // The property which contains the total dataset size (optional)
7497 root: "rows", // The property which contains an Array of row objects
7498 id: "id" // The property within each row object that provides an ID for the record (optional)
7502 * This would consume a JSON file like this:
7504 { 'results': 2, 'rows': [
7505 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
7506 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
7509 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
7510 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
7511 * paged from the remote server.
7512 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
7513 * @cfg {String} root name of the property which contains the Array of row objects.
7514 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
7516 * Create a new JsonReader
7517 * @param {Object} meta Metadata configuration options
7518 * @param {Object} recordType Either an Array of field definition objects,
7519 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
7521 Roo.data.JsonReader = function(meta, recordType){
7524 // set some defaults:
7526 totalProperty: 'total',
7527 successProperty : 'success',
7532 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
7534 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
7537 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
7538 * Used by Store query builder to append _requestMeta to params.
7541 metaFromRemote : false,
7543 * This method is only used by a DataProxy which has retrieved data from a remote server.
7544 * @param {Object} response The XHR object which contains the JSON data in its responseText.
7545 * @return {Object} data A data block which is used by an Roo.data.Store object as
7546 * a cache of Roo.data.Records.
7548 read : function(response){
7549 var json = response.responseText;
7551 var o = /* eval:var:o */ eval("("+json+")");
7553 throw {message: "JsonReader.read: Json object not found"};
7559 this.metaFromRemote = true;
7560 this.meta = o.metaData;
7561 this.recordType = Roo.data.Record.create(o.metaData.fields);
7562 this.onMetaChange(this.meta, this.recordType, o);
7564 return this.readRecords(o);
7567 // private function a store will implement
7568 onMetaChange : function(meta, recordType, o){
7575 simpleAccess: function(obj, subsc) {
7582 getJsonAccessor: function(){
7584 return function(expr) {
7586 return(re.test(expr))
7587 ? new Function("obj", "return obj." + expr)
7597 * Create a data block containing Roo.data.Records from an XML document.
7598 * @param {Object} o An object which contains an Array of row objects in the property specified
7599 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
7600 * which contains the total size of the dataset.
7601 * @return {Object} data A data block which is used by an Roo.data.Store object as
7602 * a cache of Roo.data.Records.
7604 readRecords : function(o){
7606 * After any data loads, the raw JSON data is available for further custom processing.
7610 var s = this.meta, Record = this.recordType,
7611 f = Record.prototype.fields, fi = f.items, fl = f.length;
7613 // Generate extraction functions for the totalProperty, the root, the id, and for each field
7615 if(s.totalProperty) {
7616 this.getTotal = this.getJsonAccessor(s.totalProperty);
7618 if(s.successProperty) {
7619 this.getSuccess = this.getJsonAccessor(s.successProperty);
7621 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
7623 var g = this.getJsonAccessor(s.id);
7624 this.getId = function(rec) {
7626 return (r === undefined || r === "") ? null : r;
7629 this.getId = function(){return null;};
7632 for(var jj = 0; jj < fl; jj++){
7634 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
7635 this.ef[jj] = this.getJsonAccessor(map);
7639 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
7640 if(s.totalProperty){
7641 var vt = parseInt(this.getTotal(o), 10);
7646 if(s.successProperty){
7647 var vs = this.getSuccess(o);
7648 if(vs === false || vs === 'false'){
7653 for(var i = 0; i < c; i++){
7656 var id = this.getId(n);
7657 for(var j = 0; j < fl; j++){
7659 var v = this.ef[j](n);
7661 Roo.log('missing convert for ' + f.name);
7665 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
7667 var record = new Record(values, id);
7669 records[i] = record;
7675 totalRecords : totalRecords
7680 * Ext JS Library 1.1.1
7681 * Copyright(c) 2006-2007, Ext JS, LLC.
7683 * Originally Released Under LGPL - original licence link has changed is not relivant.
7686 * <script type="text/javascript">
7690 * @class Roo.data.ArrayReader
7691 * @extends Roo.data.DataReader
7692 * Data reader class to create an Array of Roo.data.Record objects from an Array.
7693 * Each element of that Array represents a row of data fields. The
7694 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
7695 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
7699 var RecordDef = Roo.data.Record.create([
7700 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
7701 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
7703 var myReader = new Roo.data.ArrayReader({
7704 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
7708 * This would consume an Array like this:
7710 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
7712 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
7714 * Create a new JsonReader
7715 * @param {Object} meta Metadata configuration options.
7716 * @param {Object} recordType Either an Array of field definition objects
7717 * as specified to {@link Roo.data.Record#create},
7718 * or an {@link Roo.data.Record} object
7719 * created using {@link Roo.data.Record#create}.
7721 Roo.data.ArrayReader = function(meta, recordType){
7722 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
7725 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
7727 * Create a data block containing Roo.data.Records from an XML document.
7728 * @param {Object} o An Array of row objects which represents the dataset.
7729 * @return {Object} data A data block which is used by an Roo.data.Store object as
7730 * a cache of Roo.data.Records.
7732 readRecords : function(o){
7733 var sid = this.meta ? this.meta.id : null;
7734 var recordType = this.recordType, fields = recordType.prototype.fields;
7737 for(var i = 0; i < root.length; i++){
7740 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
7741 for(var j = 0, jlen = fields.length; j < jlen; j++){
7742 var f = fields.items[j];
7743 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
7744 var v = n[k] !== undefined ? n[k] : f.defaultValue;
7748 var record = new recordType(values, id);
7750 records[records.length] = record;
7754 totalRecords : records.length
7763 * @class Roo.bootstrap.ComboBox
7764 * @extends Roo.bootstrap.TriggerField
7765 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
7766 * @cfg {Boolean} append (true|false) default false
7768 * Create a new ComboBox.
7769 * @param {Object} config Configuration options
7771 Roo.bootstrap.ComboBox = function(config){
7772 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
7776 * Fires when the dropdown list is expanded
7777 * @param {Roo.bootstrap.ComboBox} combo This combo box
7782 * Fires when the dropdown list is collapsed
7783 * @param {Roo.bootstrap.ComboBox} combo This combo box
7787 * @event beforeselect
7788 * Fires before a list item is selected. Return false to cancel the selection.
7789 * @param {Roo.bootstrap.ComboBox} combo This combo box
7790 * @param {Roo.data.Record} record The data record returned from the underlying store
7791 * @param {Number} index The index of the selected item in the dropdown list
7793 'beforeselect' : true,
7796 * Fires when a list item is selected
7797 * @param {Roo.bootstrap.ComboBox} combo This combo box
7798 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
7799 * @param {Number} index The index of the selected item in the dropdown list
7803 * @event beforequery
7804 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
7805 * The event object passed has these properties:
7806 * @param {Roo.bootstrap.ComboBox} combo This combo box
7807 * @param {String} query The query
7808 * @param {Boolean} forceAll true to force "all" query
7809 * @param {Boolean} cancel true to cancel the query
7810 * @param {Object} e The query event object
7812 'beforequery': true,
7815 * Fires when the 'add' icon is pressed (add a listener to enable add button)
7816 * @param {Roo.bootstrap.ComboBox} combo This combo box
7821 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
7822 * @param {Roo.bootstrap.ComboBox} combo This combo box
7823 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
7828 * Fires when the remove value from the combobox array
7829 * @param {Roo.bootstrap.ComboBox} combo This combo box
7836 this.selectedIndex = -1;
7837 if(this.mode == 'local'){
7838 if(config.queryDelay === undefined){
7839 this.queryDelay = 10;
7841 if(config.minChars === undefined){
7847 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
7850 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
7851 * rendering into an Roo.Editor, defaults to false)
7854 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
7855 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
7858 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
7861 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
7862 * the dropdown list (defaults to undefined, with no header element)
7866 * @cfg {String/Roo.Template} tpl The template to use to render the output
7870 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
7872 listWidth: undefined,
7874 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
7875 * mode = 'remote' or 'text' if mode = 'local')
7877 displayField: undefined,
7879 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
7880 * mode = 'remote' or 'value' if mode = 'local').
7881 * Note: use of a valueField requires the user make a selection
7882 * in order for a value to be mapped.
7884 valueField: undefined,
7888 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
7889 * field's data value (defaults to the underlying DOM element's name)
7891 hiddenName: undefined,
7893 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
7897 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
7899 selectedClass: 'active',
7902 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
7906 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
7907 * anchor positions (defaults to 'tl-bl')
7909 listAlign: 'tl-bl?',
7911 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
7915 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
7916 * query specified by the allQuery config option (defaults to 'query')
7918 triggerAction: 'query',
7920 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
7921 * (defaults to 4, does not apply if editable = false)
7925 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
7926 * delay (typeAheadDelay) if it matches a known value (defaults to false)
7930 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
7931 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
7935 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
7936 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
7940 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
7941 * when editable = true (defaults to false)
7943 selectOnFocus:false,
7945 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
7947 queryParam: 'query',
7949 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
7950 * when mode = 'remote' (defaults to 'Loading...')
7952 loadingText: 'Loading...',
7954 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
7958 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
7962 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
7963 * traditional select (defaults to true)
7967 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
7971 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
7975 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
7976 * listWidth has a higher value)
7980 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
7981 * allow the user to set arbitrary text into the field (defaults to false)
7983 forceSelection:false,
7985 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
7986 * if typeAhead = true (defaults to 250)
7988 typeAheadDelay : 250,
7990 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
7991 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
7993 valueNotFoundText : undefined,
7995 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
8000 * @cfg {Boolean} disableClear Disable showing of clear button.
8002 disableClear : false,
8004 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
8006 alwaysQuery : false,
8009 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
8023 // element that contains real text value.. (when hidden is used..)
8026 initEvents: function(){
8029 throw "can not find store for combo";
8031 this.store = Roo.factory(this.store, Roo.data);
8035 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
8038 if(this.hiddenName){
8040 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
8042 this.hiddenField.dom.value =
8043 this.hiddenValue !== undefined ? this.hiddenValue :
8044 this.value !== undefined ? this.value : '';
8046 // prevent input submission
8047 this.el.dom.removeAttribute('name');
8048 this.hiddenField.dom.setAttribute('name', this.hiddenName);
8053 // this.el.dom.setAttribute('autocomplete', 'off');
8056 var cls = 'x-combo-list';
8057 this.list = this.el.select('ul.dropdown-menu',true).first();
8059 //this.list = new Roo.Layer({
8060 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
8063 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
8064 this.list.setWidth(lw);
8066 this.list.on('mouseover', this.onViewOver, this);
8067 this.list.on('mousemove', this.onViewMove, this);
8069 this.list.on('scroll', this.onViewScroll, this);
8072 this.list.swallowEvent('mousewheel');
8073 this.assetHeight = 0;
8076 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
8077 this.assetHeight += this.header.getHeight();
8080 this.innerList = this.list.createChild({cls:cls+'-inner'});
8081 this.innerList.on('mouseover', this.onViewOver, this);
8082 this.innerList.on('mousemove', this.onViewMove, this);
8083 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
8085 if(this.allowBlank && !this.pageSize && !this.disableClear){
8086 this.footer = this.list.createChild({cls:cls+'-ft'});
8087 this.pageTb = new Roo.Toolbar(this.footer);
8091 this.footer = this.list.createChild({cls:cls+'-ft'});
8092 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
8093 {pageSize: this.pageSize});
8097 if (this.pageTb && this.allowBlank && !this.disableClear) {
8099 this.pageTb.add(new Roo.Toolbar.Fill(), {
8100 cls: 'x-btn-icon x-btn-clear',
8106 _this.onSelect(false, -1);
8111 this.assetHeight += this.footer.getHeight();
8116 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
8119 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
8120 singleSelect:true, store: this.store, selectedClass: this.selectedClass
8122 //this.view.wrapEl.setDisplayed(false);
8123 this.view.on('click', this.onViewClick, this);
8127 this.store.on('beforeload', this.onBeforeLoad, this);
8128 this.store.on('load', this.onLoad, this);
8129 this.store.on('loadexception', this.onLoadException, this);
8132 this.resizer = new Roo.Resizable(this.list, {
8133 pinned:true, handles:'se'
8135 this.resizer.on('resize', function(r, w, h){
8136 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
8138 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
8139 this.restrictHeight();
8141 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
8145 this.editable = true;
8146 this.setEditable(false);
8151 if (typeof(this.events.add.listeners) != 'undefined') {
8153 this.addicon = this.wrap.createChild(
8154 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
8156 this.addicon.on('click', function(e) {
8157 this.fireEvent('add', this);
8160 if (typeof(this.events.edit.listeners) != 'undefined') {
8162 this.editicon = this.wrap.createChild(
8163 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
8165 this.editicon.setStyle('margin-left', '40px');
8167 this.editicon.on('click', function(e) {
8169 // we fire even if inothing is selected..
8170 this.fireEvent('edit', this, this.lastData );
8176 this.keyNav = new Roo.KeyNav(this.inputEl(), {
8178 this.inKeyMode = true;
8182 "down" : function(e){
8183 if(!this.isExpanded()){
8184 this.onTriggerClick();
8186 this.inKeyMode = true;
8191 "enter" : function(e){
8196 "esc" : function(e){
8200 "tab" : function(e){
8203 if(this.fireEvent("specialkey", this, e)){
8204 this.onViewClick(false);
8212 doRelay : function(foo, bar, hname){
8213 if(hname == 'down' || this.scope.isExpanded()){
8214 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
8223 this.queryDelay = Math.max(this.queryDelay || 10,
8224 this.mode == 'local' ? 10 : 250);
8227 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
8230 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
8232 if(this.editable !== false){
8233 this.inputEl().on("keyup", this.onKeyUp, this);
8235 if(this.forceSelection){
8236 this.on('blur', this.doForce, this);
8240 this.choices = this.el.select('ul.select2-choices', true).first();
8241 this.searchField = this.el.select('ul li.select2-search-field', true).first();
8245 onDestroy : function(){
8247 this.view.setStore(null);
8248 this.view.el.removeAllListeners();
8249 this.view.el.remove();
8250 this.view.purgeListeners();
8253 this.list.dom.innerHTML = '';
8256 this.store.un('beforeload', this.onBeforeLoad, this);
8257 this.store.un('load', this.onLoad, this);
8258 this.store.un('loadexception', this.onLoadException, this);
8260 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
8264 fireKey : function(e){
8265 if(e.isNavKeyPress() && !this.list.isVisible()){
8266 this.fireEvent("specialkey", this, e);
8271 onResize: function(w, h){
8272 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
8274 // if(typeof w != 'number'){
8275 // // we do not handle it!?!?
8278 // var tw = this.trigger.getWidth();
8279 // // tw += this.addicon ? this.addicon.getWidth() : 0;
8280 // // tw += this.editicon ? this.editicon.getWidth() : 0;
8282 // this.inputEl().setWidth( this.adjustWidth('input', x));
8284 // //this.trigger.setStyle('left', x+'px');
8286 // if(this.list && this.listWidth === undefined){
8287 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
8288 // this.list.setWidth(lw);
8289 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
8297 * Allow or prevent the user from directly editing the field text. If false is passed,
8298 * the user will only be able to select from the items defined in the dropdown list. This method
8299 * is the runtime equivalent of setting the 'editable' config option at config time.
8300 * @param {Boolean} value True to allow the user to directly edit the field text
8302 setEditable : function(value){
8303 if(value == this.editable){
8306 this.editable = value;
8308 this.inputEl().dom.setAttribute('readOnly', true);
8309 this.inputEl().on('mousedown', this.onTriggerClick, this);
8310 this.inputEl().addClass('x-combo-noedit');
8312 this.inputEl().dom.setAttribute('readOnly', false);
8313 this.inputEl().un('mousedown', this.onTriggerClick, this);
8314 this.inputEl().removeClass('x-combo-noedit');
8320 onBeforeLoad : function(combo,opts){
8325 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
8327 this.restrictHeight();
8328 this.selectedIndex = -1;
8332 onLoad : function(){
8334 this.hasQuery = false;
8340 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
8341 this.loading.hide();
8344 if(this.store.getCount() > 0){
8346 this.restrictHeight();
8347 if(this.lastQuery == this.allQuery){
8349 this.inputEl().dom.select();
8351 if(!this.selectByValue(this.value, true)){
8352 this.select(0, true);
8356 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
8357 this.taTask.delay(this.typeAheadDelay);
8361 this.onEmptyResults();
8367 onLoadException : function()
8369 this.hasQuery = false;
8371 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
8372 this.loading.hide();
8376 Roo.log(this.store.reader.jsonData);
8377 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
8379 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
8385 onTypeAhead : function(){
8386 if(this.store.getCount() > 0){
8387 var r = this.store.getAt(0);
8388 var newValue = r.data[this.displayField];
8389 var len = newValue.length;
8390 var selStart = this.getRawValue().length;
8392 if(selStart != len){
8393 this.setRawValue(newValue);
8394 this.selectText(selStart, newValue.length);
8400 onSelect : function(record, index){
8402 if(this.fireEvent('beforeselect', this, record, index) !== false){
8404 this.setFromData(index > -1 ? record.data : false);
8407 this.fireEvent('select', this, record, index);
8412 * Returns the currently selected field value or empty string if no value is set.
8413 * @return {String} value The selected value
8415 getValue : function(){
8418 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
8421 if(this.valueField){
8422 return typeof this.value != 'undefined' ? this.value : '';
8424 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
8429 * Clears any text/value currently set in the field
8431 clearValue : function(){
8432 if(this.hiddenField){
8433 this.hiddenField.dom.value = '';
8436 this.setRawValue('');
8437 this.lastSelectionText = '';
8442 * Sets the specified value into the field. If the value finds a match, the corresponding record text
8443 * will be displayed in the field. If the value does not match the data value of an existing item,
8444 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
8445 * Otherwise the field will be blank (although the value will still be set).
8446 * @param {String} value The value to match
8448 setValue : function(v){
8455 if(this.valueField){
8456 var r = this.findRecord(this.valueField, v);
8458 text = r.data[this.displayField];
8459 }else if(this.valueNotFoundText !== undefined){
8460 text = this.valueNotFoundText;
8463 this.lastSelectionText = text;
8464 if(this.hiddenField){
8465 this.hiddenField.dom.value = v;
8467 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
8471 * @property {Object} the last set data for the element
8476 * Sets the value of the field based on a object which is related to the record format for the store.
8477 * @param {Object} value the value to set as. or false on reset?
8479 setFromData : function(o){
8486 var dv = ''; // display value
8487 var vv = ''; // value value..
8489 if (this.displayField) {
8490 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
8492 // this is an error condition!!!
8493 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
8496 if(this.valueField){
8497 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
8500 if(this.hiddenField){
8501 this.hiddenField.dom.value = vv;
8503 this.lastSelectionText = dv;
8504 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
8508 // no hidden field.. - we store the value in 'value', but still display
8509 // display field!!!!
8510 this.lastSelectionText = dv;
8511 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
8518 // overridden so that last data is reset..
8519 this.setValue(this.originalValue);
8520 this.clearInvalid();
8521 this.lastData = false;
8523 this.view.clearSelections();
8527 findRecord : function(prop, value){
8529 if(this.store.getCount() > 0){
8530 this.store.each(function(r){
8531 if(r.data[prop] == value){
8543 // returns hidden if it's set..
8544 if (!this.rendered) {return ''};
8545 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
8549 onViewMove : function(e, t){
8550 this.inKeyMode = false;
8554 onViewOver : function(e, t){
8555 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
8558 var item = this.view.findItemFromChild(t);
8560 var index = this.view.indexOf(item);
8561 this.select(index, false);
8566 onViewClick : function(doFocus)
8568 var index = this.view.getSelectedIndexes()[0];
8569 var r = this.store.getAt(index);
8571 this.onSelect(r, index);
8573 if(doFocus !== false && !this.blockFocus){
8574 this.inputEl().focus();
8579 restrictHeight : function(){
8580 //this.innerList.dom.style.height = '';
8581 //var inner = this.innerList.dom;
8582 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
8583 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
8584 //this.list.beginUpdate();
8585 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
8586 this.list.alignTo(this.inputEl(), this.listAlign);
8587 //this.list.endUpdate();
8591 onEmptyResults : function(){
8596 * Returns true if the dropdown list is expanded, else false.
8598 isExpanded : function(){
8599 return this.list.isVisible();
8603 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
8604 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
8605 * @param {String} value The data value of the item to select
8606 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
8607 * selected item if it is not currently in view (defaults to true)
8608 * @return {Boolean} True if the value matched an item in the list, else false
8610 selectByValue : function(v, scrollIntoView){
8611 if(v !== undefined && v !== null){
8612 var r = this.findRecord(this.valueField || this.displayField, v);
8614 this.select(this.store.indexOf(r), scrollIntoView);
8622 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
8623 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
8624 * @param {Number} index The zero-based index of the list item to select
8625 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
8626 * selected item if it is not currently in view (defaults to true)
8628 select : function(index, scrollIntoView){
8629 this.selectedIndex = index;
8630 this.view.select(index);
8631 if(scrollIntoView !== false){
8632 var el = this.view.getNode(index);
8634 //this.innerList.scrollChildIntoView(el, false);
8641 selectNext : function(){
8642 var ct = this.store.getCount();
8644 if(this.selectedIndex == -1){
8646 }else if(this.selectedIndex < ct-1){
8647 this.select(this.selectedIndex+1);
8653 selectPrev : function(){
8654 var ct = this.store.getCount();
8656 if(this.selectedIndex == -1){
8658 }else if(this.selectedIndex != 0){
8659 this.select(this.selectedIndex-1);
8665 onKeyUp : function(e){
8666 if(this.editable !== false && !e.isSpecialKey()){
8667 this.lastKey = e.getKey();
8668 this.dqTask.delay(this.queryDelay);
8673 validateBlur : function(){
8674 return !this.list || !this.list.isVisible();
8678 initQuery : function(){
8679 this.doQuery(this.getRawValue());
8683 doForce : function(){
8684 if(this.el.dom.value.length > 0){
8686 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
8692 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
8693 * query allowing the query action to be canceled if needed.
8694 * @param {String} query The SQL query to execute
8695 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
8696 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
8697 * saved in the current store (defaults to false)
8699 doQuery : function(q, forceAll){
8701 if(q === undefined || q === null){
8710 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
8715 forceAll = qe.forceAll;
8716 if(forceAll === true || (q.length >= this.minChars)){
8718 this.hasQuery = true;
8720 if(this.lastQuery != q || this.alwaysQuery){
8722 if(this.mode == 'local'){
8723 this.selectedIndex = -1;
8725 this.store.clearFilter();
8727 this.store.filter(this.displayField, q);
8731 this.store.baseParams[this.queryParam] = q;
8733 var options = {params : this.getParams(q)};
8737 options.params.start = this.page * this.pageSize;
8740 this.store.load(options);
8744 this.selectedIndex = -1;
8749 this.loadNext = false;
8753 getParams : function(q){
8755 //p[this.queryParam] = q;
8759 p.limit = this.pageSize;
8765 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
8767 collapse : function(){
8768 if(!this.isExpanded()){
8773 Roo.get(document).un('mousedown', this.collapseIf, this);
8774 Roo.get(document).un('mousewheel', this.collapseIf, this);
8775 if (!this.editable) {
8776 Roo.get(document).un('keydown', this.listKeyPress, this);
8778 this.fireEvent('collapse', this);
8782 collapseIf : function(e){
8783 var in_combo = e.within(this.el);
8784 var in_list = e.within(this.list);
8786 if (in_combo || in_list) {
8787 //e.stopPropagation();
8796 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
8798 expand : function(){
8800 if(this.isExpanded() || !this.hasFocus){
8804 this.list.alignTo(this.inputEl(), this.listAlign);
8806 Roo.get(document).on('mousedown', this.collapseIf, this);
8807 Roo.get(document).on('mousewheel', this.collapseIf, this);
8808 if (!this.editable) {
8809 Roo.get(document).on('keydown', this.listKeyPress, this);
8812 this.fireEvent('expand', this);
8816 // Implements the default empty TriggerField.onTriggerClick function
8817 onTriggerClick : function()
8819 Roo.log('trigger click');
8826 this.loadNext = false;
8828 if(this.isExpanded()){
8830 if (!this.blockFocus) {
8831 this.inputEl().focus();
8835 this.hasFocus = true;
8836 if(this.triggerAction == 'all') {
8837 this.doQuery(this.allQuery, true);
8839 this.doQuery(this.getRawValue());
8841 if (!this.blockFocus) {
8842 this.inputEl().focus();
8846 listKeyPress : function(e)
8848 //Roo.log('listkeypress');
8849 // scroll to first matching element based on key pres..
8850 if (e.isSpecialKey()) {
8853 var k = String.fromCharCode(e.getKey()).toUpperCase();
8856 var csel = this.view.getSelectedNodes();
8857 var cselitem = false;
8859 var ix = this.view.indexOf(csel[0]);
8860 cselitem = this.store.getAt(ix);
8861 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
8867 this.store.each(function(v) {
8869 // start at existing selection.
8870 if (cselitem.id == v.id) {
8876 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
8877 match = this.store.indexOf(v);
8883 if (match === false) {
8884 return true; // no more action?
8887 this.view.select(match);
8888 var sn = Roo.get(this.view.getSelectedNodes()[0])
8889 //sn.scrollIntoView(sn.dom.parentNode, false);
8892 onViewScroll : function(e, t){
8894 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
8898 this.hasQuery = true;
8900 this.loading = this.list.select('.loading', true).first();
8902 if(this.loading === null){
8903 this.list.createChild({
8905 cls: 'loading select2-more-results select2-active',
8906 html: 'Loading more results...'
8909 this.loading = this.list.select('.loading', true).first();
8911 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
8913 this.loading.hide();
8916 this.loading.show();
8921 this.loadNext = true;
8923 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
8928 addItem : function(o)
8930 var dv = ''; // display value
8932 if (this.displayField) {
8933 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
8935 // this is an error condition!!!
8936 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
8943 var choice = this.choices.createChild({
8945 cls: 'select2-search-choice',
8954 cls: 'select2-search-choice-close',
8959 }, this.searchField);
8961 var close = choice.select('a.select2-search-choice-close', true).first()
8963 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
8970 this.inputEl().dom.value = '';
8974 onRemoveItem : function(e, _self, o)
8976 Roo.log('remove item');
8977 var index = this.item.indexOf(o.data) * 1;
8980 Roo.log('not this item?!');
8984 this.item.splice(index, 1);
8989 this.fireEvent('remove', this);
8993 syncValue : function()
8995 if(!this.item.length){
9002 Roo.each(this.item, function(i){
9003 if(_this.valueField){
9004 value.push(i[_this.valueField]);
9011 this.value = value.join(',');
9013 if(this.hiddenField){
9014 this.hiddenField.dom.value = this.value;
9018 clearItem : function()
9026 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
9036 * @cfg {Boolean} grow
9040 * @cfg {Number} growMin
9044 * @cfg {Number} growMax
9054 * Ext JS Library 1.1.1
9055 * Copyright(c) 2006-2007, Ext JS, LLC.
9057 * Originally Released Under LGPL - original licence link has changed is not relivant.
9060 * <script type="text/javascript">
9065 * @extends Roo.util.Observable
9066 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
9067 * This class also supports single and multi selection modes. <br>
9068 * Create a data model bound view:
9070 var store = new Roo.data.Store(...);
9072 var view = new Roo.View({
9074 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
9077 selectedClass: "ydataview-selected",
9081 // listen for node click?
9082 view.on("click", function(vw, index, node, e){
9083 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9087 dataModel.load("foobar.xml");
9089 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
9091 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
9092 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
9094 * Note: old style constructor is still suported (container, template, config)
9098 * @param {Object} config The config object
9101 Roo.View = function(config, depreciated_tpl, depreciated_config){
9103 if (typeof(depreciated_tpl) == 'undefined') {
9104 // new way.. - universal constructor.
9105 Roo.apply(this, config);
9106 this.el = Roo.get(this.el);
9109 this.el = Roo.get(config);
9110 this.tpl = depreciated_tpl;
9111 Roo.apply(this, depreciated_config);
9113 this.wrapEl = this.el.wrap().wrap();
9114 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
9117 if(typeof(this.tpl) == "string"){
9118 this.tpl = new Roo.Template(this.tpl);
9120 // support xtype ctors..
9121 this.tpl = new Roo.factory(this.tpl, Roo);
9133 * @event beforeclick
9134 * Fires before a click is processed. Returns false to cancel the default action.
9135 * @param {Roo.View} this
9136 * @param {Number} index The index of the target node
9137 * @param {HTMLElement} node The target node
9138 * @param {Roo.EventObject} e The raw event object
9140 "beforeclick" : true,
9143 * Fires when a template node is clicked.
9144 * @param {Roo.View} this
9145 * @param {Number} index The index of the target node
9146 * @param {HTMLElement} node The target node
9147 * @param {Roo.EventObject} e The raw event object
9152 * Fires when a template node is double clicked.
9153 * @param {Roo.View} this
9154 * @param {Number} index The index of the target node
9155 * @param {HTMLElement} node The target node
9156 * @param {Roo.EventObject} e The raw event object
9160 * @event contextmenu
9161 * Fires when a template node is right clicked.
9162 * @param {Roo.View} this
9163 * @param {Number} index The index of the target node
9164 * @param {HTMLElement} node The target node
9165 * @param {Roo.EventObject} e The raw event object
9167 "contextmenu" : true,
9169 * @event selectionchange
9170 * Fires when the selected nodes change.
9171 * @param {Roo.View} this
9172 * @param {Array} selections Array of the selected nodes
9174 "selectionchange" : true,
9177 * @event beforeselect
9178 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
9179 * @param {Roo.View} this
9180 * @param {HTMLElement} node The node to be selected
9181 * @param {Array} selections Array of currently selected nodes
9183 "beforeselect" : true,
9185 * @event preparedata
9186 * Fires on every row to render, to allow you to change the data.
9187 * @param {Roo.View} this
9188 * @param {Object} data to be rendered (change this)
9190 "preparedata" : true
9198 "click": this.onClick,
9199 "dblclick": this.onDblClick,
9200 "contextmenu": this.onContextMenu,
9204 this.selections = [];
9206 this.cmp = new Roo.CompositeElementLite([]);
9208 this.store = Roo.factory(this.store, Roo.data);
9209 this.setStore(this.store, true);
9212 if ( this.footer && this.footer.xtype) {
9214 var fctr = this.wrapEl.appendChild(document.createElement("div"));
9216 this.footer.dataSource = this.store
9217 this.footer.container = fctr;
9218 this.footer = Roo.factory(this.footer, Roo);
9219 fctr.insertFirst(this.el);
9221 // this is a bit insane - as the paging toolbar seems to detach the el..
9222 // dom.parentNode.parentNode.parentNode
9223 // they get detached?
9227 Roo.View.superclass.constructor.call(this);
9232 Roo.extend(Roo.View, Roo.util.Observable, {
9235 * @cfg {Roo.data.Store} store Data store to load data from.
9240 * @cfg {String|Roo.Element} el The container element.
9245 * @cfg {String|Roo.Template} tpl The template used by this View
9249 * @cfg {String} dataName the named area of the template to use as the data area
9250 * Works with domtemplates roo-name="name"
9254 * @cfg {String} selectedClass The css class to add to selected nodes
9256 selectedClass : "x-view-selected",
9258 * @cfg {String} emptyText The empty text to show when nothing is loaded.
9263 * @cfg {String} text to display on mask (default Loading)
9267 * @cfg {Boolean} multiSelect Allow multiple selection
9269 multiSelect : false,
9271 * @cfg {Boolean} singleSelect Allow single selection
9273 singleSelect: false,
9276 * @cfg {Boolean} toggleSelect - selecting
9278 toggleSelect : false,
9281 * Returns the element this view is bound to.
9282 * @return {Roo.Element}
9291 * Refreshes the view. - called by datachanged on the store. - do not call directly.
9293 refresh : function(){
9297 // if we are using something like 'domtemplate', then
9298 // the what gets used is:
9299 // t.applySubtemplate(NAME, data, wrapping data..)
9300 // the outer template then get' applied with
9301 // the store 'extra data'
9302 // and the body get's added to the
9303 // roo-name="data" node?
9304 // <span class='roo-tpl-{name}'></span> ?????
9308 this.clearSelections();
9311 var records = this.store.getRange();
9312 if(records.length < 1) {
9314 // is this valid?? = should it render a template??
9316 this.el.update(this.emptyText);
9320 if (this.dataName) {
9321 this.el.update(t.apply(this.store.meta)); //????
9322 el = this.el.child('.roo-tpl-' + this.dataName);
9325 for(var i = 0, len = records.length; i < len; i++){
9326 var data = this.prepareData(records[i].data, i, records[i]);
9327 this.fireEvent("preparedata", this, data, i, records[i]);
9328 html[html.length] = Roo.util.Format.trim(
9330 t.applySubtemplate(this.dataName, data, this.store.meta) :
9337 el.update(html.join(""));
9338 this.nodes = el.dom.childNodes;
9339 this.updateIndexes(0);
9344 * Function to override to reformat the data that is sent to
9345 * the template for each node.
9346 * DEPRICATED - use the preparedata event handler.
9347 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
9348 * a JSON object for an UpdateManager bound view).
9350 prepareData : function(data, index, record)
9352 this.fireEvent("preparedata", this, data, index, record);
9356 onUpdate : function(ds, record){
9357 Roo.log('on update');
9358 this.clearSelections();
9359 var index = this.store.indexOf(record);
9360 var n = this.nodes[index];
9361 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
9362 n.parentNode.removeChild(n);
9363 this.updateIndexes(index, index);
9369 onAdd : function(ds, records, index)
9371 Roo.log(['on Add', ds, records, index] );
9372 this.clearSelections();
9373 if(this.nodes.length == 0){
9377 var n = this.nodes[index];
9378 for(var i = 0, len = records.length; i < len; i++){
9379 var d = this.prepareData(records[i].data, i, records[i]);
9381 this.tpl.insertBefore(n, d);
9384 this.tpl.append(this.el, d);
9387 this.updateIndexes(index);
9390 onRemove : function(ds, record, index){
9391 Roo.log('onRemove');
9392 this.clearSelections();
9393 var el = this.dataName ?
9394 this.el.child('.roo-tpl-' + this.dataName) :
9397 el.dom.removeChild(this.nodes[index]);
9398 this.updateIndexes(index);
9402 * Refresh an individual node.
9403 * @param {Number} index
9405 refreshNode : function(index){
9406 this.onUpdate(this.store, this.store.getAt(index));
9409 updateIndexes : function(startIndex, endIndex){
9410 var ns = this.nodes;
9411 startIndex = startIndex || 0;
9412 endIndex = endIndex || ns.length - 1;
9413 for(var i = startIndex; i <= endIndex; i++){
9414 ns[i].nodeIndex = i;
9419 * Changes the data store this view uses and refresh the view.
9420 * @param {Store} store
9422 setStore : function(store, initial){
9423 if(!initial && this.store){
9424 this.store.un("datachanged", this.refresh);
9425 this.store.un("add", this.onAdd);
9426 this.store.un("remove", this.onRemove);
9427 this.store.un("update", this.onUpdate);
9428 this.store.un("clear", this.refresh);
9429 this.store.un("beforeload", this.onBeforeLoad);
9430 this.store.un("load", this.onLoad);
9431 this.store.un("loadexception", this.onLoad);
9435 store.on("datachanged", this.refresh, this);
9436 store.on("add", this.onAdd, this);
9437 store.on("remove", this.onRemove, this);
9438 store.on("update", this.onUpdate, this);
9439 store.on("clear", this.refresh, this);
9440 store.on("beforeload", this.onBeforeLoad, this);
9441 store.on("load", this.onLoad, this);
9442 store.on("loadexception", this.onLoad, this);
9450 * onbeforeLoad - masks the loading area.
9453 onBeforeLoad : function(store,opts)
9455 Roo.log('onBeforeLoad');
9459 this.el.mask(this.mask ? this.mask : "Loading" );
9461 onLoad : function ()
9468 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
9469 * @param {HTMLElement} node
9470 * @return {HTMLElement} The template node
9472 findItemFromChild : function(node){
9473 var el = this.dataName ?
9474 this.el.child('.roo-tpl-' + this.dataName,true) :
9477 if(!node || node.parentNode == el){
9480 var p = node.parentNode;
9481 while(p && p != el){
9482 if(p.parentNode == el){
9491 onClick : function(e){
9492 var item = this.findItemFromChild(e.getTarget());
9494 var index = this.indexOf(item);
9495 if(this.onItemClick(item, index, e) !== false){
9496 this.fireEvent("click", this, index, item, e);
9499 this.clearSelections();
9504 onContextMenu : function(e){
9505 var item = this.findItemFromChild(e.getTarget());
9507 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
9512 onDblClick : function(e){
9513 var item = this.findItemFromChild(e.getTarget());
9515 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
9519 onItemClick : function(item, index, e)
9521 if(this.fireEvent("beforeclick", this, index, item, e) === false){
9524 if (this.toggleSelect) {
9525 var m = this.isSelected(item) ? 'unselect' : 'select';
9528 _t[m](item, true, false);
9531 if(this.multiSelect || this.singleSelect){
9532 if(this.multiSelect && e.shiftKey && this.lastSelection){
9533 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
9535 this.select(item, this.multiSelect && e.ctrlKey);
9536 this.lastSelection = item;
9544 * Get the number of selected nodes.
9547 getSelectionCount : function(){
9548 return this.selections.length;
9552 * Get the currently selected nodes.
9553 * @return {Array} An array of HTMLElements
9555 getSelectedNodes : function(){
9556 return this.selections;
9560 * Get the indexes of the selected nodes.
9563 getSelectedIndexes : function(){
9564 var indexes = [], s = this.selections;
9565 for(var i = 0, len = s.length; i < len; i++){
9566 indexes.push(s[i].nodeIndex);
9572 * Clear all selections
9573 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
9575 clearSelections : function(suppressEvent){
9576 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
9577 this.cmp.elements = this.selections;
9578 this.cmp.removeClass(this.selectedClass);
9579 this.selections = [];
9581 this.fireEvent("selectionchange", this, this.selections);
9587 * Returns true if the passed node is selected
9588 * @param {HTMLElement/Number} node The node or node index
9591 isSelected : function(node){
9592 var s = this.selections;
9596 node = this.getNode(node);
9597 return s.indexOf(node) !== -1;
9602 * @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
9603 * @param {Boolean} keepExisting (optional) true to keep existing selections
9604 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
9606 select : function(nodeInfo, keepExisting, suppressEvent){
9607 if(nodeInfo instanceof Array){
9609 this.clearSelections(true);
9611 for(var i = 0, len = nodeInfo.length; i < len; i++){
9612 this.select(nodeInfo[i], true, true);
9616 var node = this.getNode(nodeInfo);
9617 if(!node || this.isSelected(node)){
9618 return; // already selected.
9621 this.clearSelections(true);
9623 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
9624 Roo.fly(node).addClass(this.selectedClass);
9625 this.selections.push(node);
9627 this.fireEvent("selectionchange", this, this.selections);
9635 * @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
9636 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
9637 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
9639 unselect : function(nodeInfo, keepExisting, suppressEvent)
9641 if(nodeInfo instanceof Array){
9642 Roo.each(this.selections, function(s) {
9643 this.unselect(s, nodeInfo);
9647 var node = this.getNode(nodeInfo);
9648 if(!node || !this.isSelected(node)){
9649 Roo.log("not selected");
9650 return; // not selected.
9654 Roo.each(this.selections, function(s) {
9656 Roo.fly(node).removeClass(this.selectedClass);
9663 this.selections= ns;
9664 this.fireEvent("selectionchange", this, this.selections);
9668 * Gets a template node.
9669 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9670 * @return {HTMLElement} The node or null if it wasn't found
9672 getNode : function(nodeInfo){
9673 if(typeof nodeInfo == "string"){
9674 return document.getElementById(nodeInfo);
9675 }else if(typeof nodeInfo == "number"){
9676 return this.nodes[nodeInfo];
9682 * Gets a range template nodes.
9683 * @param {Number} startIndex
9684 * @param {Number} endIndex
9685 * @return {Array} An array of nodes
9687 getNodes : function(start, end){
9688 var ns = this.nodes;
9690 end = typeof end == "undefined" ? ns.length - 1 : end;
9693 for(var i = start; i <= end; i++){
9697 for(var i = start; i >= end; i--){
9705 * Finds the index of the passed node
9706 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9707 * @return {Number} The index of the node or -1
9709 indexOf : function(node){
9710 node = this.getNode(node);
9711 if(typeof node.nodeIndex == "number"){
9712 return node.nodeIndex;
9714 var ns = this.nodes;
9715 for(var i = 0, len = ns.length; i < len; i++){
9726 * based on jquery fullcalendar
9730 Roo.bootstrap = Roo.bootstrap || {};
9732 * @class Roo.bootstrap.Calendar
9733 * @extends Roo.bootstrap.Component
9734 * Bootstrap Calendar class
9735 * @cfg {Boolean} loadMask (true|false) default false
9738 * Create a new Container
9739 * @param {Object} config The config object
9744 Roo.bootstrap.Calendar = function(config){
9745 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
9749 * Fires when a date is selected
9750 * @param {DatePicker} this
9751 * @param {Date} date The selected date
9755 * @event monthchange
9756 * Fires when the displayed month changes
9757 * @param {DatePicker} this
9758 * @param {Date} date The selected month
9760 'monthchange': true,
9763 * Fires when mouse over an event
9764 * @param {Calendar} this
9765 * @param {event} Event
9770 * Fires when the mouse leaves an
9771 * @param {Calendar} this
9777 * Fires when the mouse click an
9778 * @param {Calendar} this
9787 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
9790 * @cfg {Number} startDay
9791 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
9797 getAutoCreate : function(){
9800 var fc_button = function(name, corner, style, content ) {
9801 return Roo.apply({},{
9803 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
9805 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
9808 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
9816 style : 'width:100%',
9823 cls : 'fc-header-left',
9825 fc_button('prev', 'left', 'arrow', '‹' ),
9826 fc_button('next', 'right', 'arrow', '›' ),
9827 { tag: 'span', cls: 'fc-header-space' },
9828 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
9836 cls : 'fc-header-center',
9840 cls: 'fc-header-title',
9843 html : 'month / year'
9851 cls : 'fc-header-right',
9853 /* fc_button('month', 'left', '', 'month' ),
9854 fc_button('week', '', '', 'week' ),
9855 fc_button('day', 'right', '', 'day' )
9867 var cal_heads = function() {
9869 // fixme - handle this.
9871 for (var i =0; i < Date.dayNames.length; i++) {
9872 var d = Date.dayNames[i];
9875 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
9876 html : d.substring(0,3)
9880 ret[0].cls += ' fc-first';
9881 ret[6].cls += ' fc-last';
9884 var cal_cell = function(n) {
9887 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
9892 cls: 'fc-day-number',
9896 cls: 'fc-day-content',
9900 style: 'position: relative;' // height: 17px;
9912 var cal_rows = function() {
9915 for (var r = 0; r < 6; r++) {
9922 for (var i =0; i < Date.dayNames.length; i++) {
9923 var d = Date.dayNames[i];
9924 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
9927 row.cn[0].cls+=' fc-first';
9928 row.cn[0].cn[0].style = 'min-height:90px';
9929 row.cn[6].cls+=' fc-last';
9933 ret[0].cls += ' fc-first';
9934 ret[4].cls += ' fc-prev-last';
9935 ret[5].cls += ' fc-last';
9942 cls: 'fc-border-separate',
9943 style : 'width:100%',
9951 cls : 'fc-first fc-last',
9970 style : "position: relative;",
9973 cls : 'fc-view fc-view-month fc-grid',
9974 style : 'position: relative',
9975 unselectable : 'on',
9978 cls : 'fc-event-container',
9979 style : 'position:absolute;z-index:8;top:0;left:0;'
9997 initEvents : function()
10000 throw "can not find store for calendar";
10006 style: "text-align:center",
10010 style: "background-color:white;width:50%;margin:250 auto",
10014 src: rootURL + '/roojs1/images/ux/lightbox/loading.gif'
10025 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
10027 var size = this.el.select('.fc-content', true).first().getSize();
10028 this.maskEl.setSize(size.width, size.height);
10029 this.maskEl.enableDisplayMode("block");
10030 if(!this.loadMask){
10031 this.maskEl.hide();
10034 this.store = Roo.factory(this.store, Roo.data);
10035 this.store.on('load', this.onLoad, this);
10036 this.store.on('beforeload', this.onBeforeLoad, this);
10040 this.cells = this.el.select('.fc-day',true);
10041 //Roo.log(this.cells);
10042 this.textNodes = this.el.query('.fc-day-number');
10043 this.cells.addClassOnOver('fc-state-hover');
10045 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
10046 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
10047 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
10048 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
10050 this.on('monthchange', this.onMonthChange, this);
10052 this.update(new Date().clearTime());
10055 resize : function() {
10056 var sz = this.el.getSize();
10058 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
10059 this.el.select('.fc-day-content div',true).setHeight(34);
10064 showPrevMonth : function(e){
10065 this.update(this.activeDate.add("mo", -1));
10067 showToday : function(e){
10068 this.update(new Date().clearTime());
10071 showNextMonth : function(e){
10072 this.update(this.activeDate.add("mo", 1));
10076 showPrevYear : function(){
10077 this.update(this.activeDate.add("y", -1));
10081 showNextYear : function(){
10082 this.update(this.activeDate.add("y", 1));
10087 update : function(date)
10089 var vd = this.activeDate;
10090 this.activeDate = date;
10091 // if(vd && this.el){
10092 // var t = date.getTime();
10093 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
10094 // Roo.log('using add remove');
10096 // this.fireEvent('monthchange', this, date);
10098 // this.cells.removeClass("fc-state-highlight");
10099 // this.cells.each(function(c){
10100 // if(c.dateValue == t){
10101 // c.addClass("fc-state-highlight");
10102 // setTimeout(function(){
10103 // try{c.dom.firstChild.focus();}catch(e){}
10113 var days = date.getDaysInMonth();
10115 var firstOfMonth = date.getFirstDateOfMonth();
10116 var startingPos = firstOfMonth.getDay()-this.startDay;
10118 if(startingPos < this.startDay){
10122 var pm = date.add(Date.MONTH, -1);
10123 var prevStart = pm.getDaysInMonth()-startingPos;
10125 this.cells = this.el.select('.fc-day',true);
10126 this.textNodes = this.el.query('.fc-day-number');
10127 this.cells.addClassOnOver('fc-state-hover');
10129 var cells = this.cells.elements;
10130 var textEls = this.textNodes;
10132 Roo.each(cells, function(cell){
10133 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
10136 days += startingPos;
10138 // convert everything to numbers so it's fast
10139 var day = 86400000;
10140 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
10143 //Roo.log(prevStart);
10145 var today = new Date().clearTime().getTime();
10146 var sel = date.clearTime().getTime();
10147 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
10148 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
10149 var ddMatch = this.disabledDatesRE;
10150 var ddText = this.disabledDatesText;
10151 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
10152 var ddaysText = this.disabledDaysText;
10153 var format = this.format;
10155 var setCellClass = function(cal, cell){
10157 //Roo.log('set Cell Class');
10159 var t = d.getTime();
10163 cell.dateValue = t;
10165 cell.className += " fc-today";
10166 cell.className += " fc-state-highlight";
10167 cell.title = cal.todayText;
10170 // disable highlight in other month..
10171 //cell.className += " fc-state-highlight";
10176 cell.className = " fc-state-disabled";
10177 cell.title = cal.minText;
10181 cell.className = " fc-state-disabled";
10182 cell.title = cal.maxText;
10186 if(ddays.indexOf(d.getDay()) != -1){
10187 cell.title = ddaysText;
10188 cell.className = " fc-state-disabled";
10191 if(ddMatch && format){
10192 var fvalue = d.dateFormat(format);
10193 if(ddMatch.test(fvalue)){
10194 cell.title = ddText.replace("%0", fvalue);
10195 cell.className = " fc-state-disabled";
10199 if (!cell.initialClassName) {
10200 cell.initialClassName = cell.dom.className;
10203 cell.dom.className = cell.initialClassName + ' ' + cell.className;
10208 for(; i < startingPos; i++) {
10209 textEls[i].innerHTML = (++prevStart);
10210 d.setDate(d.getDate()+1);
10212 cells[i].className = "fc-past fc-other-month";
10213 setCellClass(this, cells[i]);
10218 for(; i < days; i++){
10219 intDay = i - startingPos + 1;
10220 textEls[i].innerHTML = (intDay);
10221 d.setDate(d.getDate()+1);
10223 cells[i].className = ''; // "x-date-active";
10224 setCellClass(this, cells[i]);
10228 for(; i < 42; i++) {
10229 textEls[i].innerHTML = (++extraDays);
10230 d.setDate(d.getDate()+1);
10232 cells[i].className = "fc-future fc-other-month";
10233 setCellClass(this, cells[i]);
10236 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
10238 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
10240 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
10241 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
10243 if(totalRows != 6){
10244 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
10245 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
10248 this.fireEvent('monthchange', this, date);
10252 if(!this.internalRender){
10253 var main = this.el.dom.firstChild;
10254 var w = main.offsetWidth;
10255 this.el.setWidth(w + this.el.getBorderWidth("lr"));
10256 Roo.fly(main).setWidth(w);
10257 this.internalRender = true;
10258 // opera does not respect the auto grow header center column
10259 // then, after it gets a width opera refuses to recalculate
10260 // without a second pass
10261 if(Roo.isOpera && !this.secondPass){
10262 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
10263 this.secondPass = true;
10264 this.update.defer(10, this, [date]);
10271 findCell : function(dt) {
10272 dt = dt.clearTime().getTime();
10274 this.cells.each(function(c){
10275 //Roo.log("check " +c.dateValue + '?=' + dt);
10276 if(c.dateValue == dt){
10286 findCells : function(ev) {
10287 var s = ev.start.clone().clearTime().getTime();
10289 var e= ev.end.clone().clearTime().getTime();
10292 this.cells.each(function(c){
10293 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
10295 if(c.dateValue > e){
10298 if(c.dateValue < s){
10307 findBestRow: function(cells)
10311 for (var i =0 ; i < cells.length;i++) {
10312 ret = Math.max(cells[i].rows || 0,ret);
10319 addItem : function(ev)
10321 // look for vertical location slot in
10322 var cells = this.findCells(ev);
10324 ev.row = this.findBestRow(cells);
10326 // work out the location.
10330 for(var i =0; i < cells.length; i++) {
10338 if (crow.start.getY() == cells[i].getY()) {
10340 crow.end = cells[i];
10356 for (var i = 0; i < cells.length;i++) {
10357 cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
10361 this.calevents.push(ev);
10364 clearEvents: function() {
10366 if(!this.calevents){
10370 Roo.each(this.cells.elements, function(c){
10374 Roo.each(this.calevents, function(e) {
10375 Roo.each(e.els, function(el) {
10376 el.un('mouseenter' ,this.onEventEnter, this);
10377 el.un('mouseleave' ,this.onEventLeave, this);
10384 renderEvents: function()
10386 // first make sure there is enough space..
10388 this.cells.each(function(c) {
10390 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.rows * 20));
10393 for (var e = 0; e < this.calevents.length; e++) {
10394 var ev = this.calevents[e];
10395 var cells = ev.cells;
10396 var rows = ev.rows;
10398 for(var i =0; i < rows.length; i++) {
10401 // how many rows should it span..
10404 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
10405 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
10407 unselectable : "on",
10410 cls: 'fc-event-inner',
10414 // cls: 'fc-event-time',
10415 // html : cells.length > 1 ? '' : ev.time
10419 cls: 'fc-event-title',
10420 html : String.format('{0}', ev.title)
10427 cls: 'ui-resizable-handle ui-resizable-e',
10428 html : '  '
10434 cfg.cls += ' fc-event-start';
10436 if ((i+1) == rows.length) {
10437 cfg.cls += ' fc-event-end';
10440 var ctr = this.el.select('.fc-event-container',true).first();
10441 var cg = ctr.createChild(cfg);
10443 cg.on('mouseenter' ,this.onEventEnter, this, ev);
10444 cg.on('mouseleave' ,this.onEventLeave, this, ev);
10445 cg.on('click', this.onEventClick, this, ev);
10449 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
10450 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
10452 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
10453 cg.setWidth(ebox.right - sbox.x -2);
10461 onEventEnter: function (e, el,event,d) {
10462 this.fireEvent('evententer', this, el, event);
10465 onEventLeave: function (e, el,event,d) {
10466 this.fireEvent('eventleave', this, el, event);
10469 onEventClick: function (e, el,event,d) {
10470 this.fireEvent('eventclick', this, el, event);
10473 onMonthChange: function () {
10477 onLoad: function ()
10479 this.calevents = [];
10482 if(this.store.getCount() > 0){
10483 this.store.data.each(function(d){
10486 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
10487 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
10488 time : d.data.start_time,
10489 title : d.data.title,
10490 description : d.data.description,
10491 venue : d.data.venue
10496 this.renderEvents();
10499 this.maskEl.hide();
10503 onBeforeLoad: function()
10505 this.clearEvents();
10508 this.maskEl.show();
10522 * @class Roo.bootstrap.Popover
10523 * @extends Roo.bootstrap.Component
10524 * Bootstrap Popover class
10525 * @cfg {String} html contents of the popover (or false to use children..)
10526 * @cfg {String} title of popover (or false to hide)
10527 * @cfg {String} placement how it is placed
10528 * @cfg {String} trigger click || hover (or false to trigger manually)
10529 * @cfg {String} over what (parent or false to trigger manually.)
10532 * Create a new Popover
10533 * @param {Object} config The config object
10536 Roo.bootstrap.Popover = function(config){
10537 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
10540 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
10542 title: 'Fill in a title',
10545 placement : 'right',
10546 trigger : 'hover', // hover
10550 can_build_overlaid : false,
10552 getChildContainer : function()
10554 return this.el.select('.popover-content',true).first();
10557 getAutoCreate : function(){
10558 Roo.log('make popover?');
10560 cls : 'popover roo-dynamic',
10561 style: 'display:block',
10567 cls : 'popover-inner',
10571 cls: 'popover-title',
10575 cls : 'popover-content',
10586 setTitle: function(str)
10588 this.el.select('.popover-title',true).first().dom.innerHTML = str;
10590 setContent: function(str)
10592 this.el.select('.popover-content',true).first().dom.innerHTML = str;
10594 // as it get's added to the bottom of the page.
10595 onRender : function(ct, position)
10597 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
10599 var cfg = Roo.apply({}, this.getAutoCreate());
10603 cfg.cls += ' ' + this.cls;
10606 cfg.style = this.style;
10608 Roo.log("adding to ")
10609 this.el = Roo.get(document.body).createChild(cfg, position);
10615 initEvents : function()
10617 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
10618 this.el.enableDisplayMode('block');
10620 if (this.over === false) {
10623 if (this.triggers === false) {
10626 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
10627 var triggers = this.trigger ? this.trigger.split(' ') : [];
10628 Roo.each(triggers, function(trigger) {
10630 if (trigger == 'click') {
10631 on_el.on('click', this.toggle, this);
10632 } else if (trigger != 'manual') {
10633 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
10634 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
10636 on_el.on(eventIn ,this.enter, this);
10637 on_el.on(eventOut, this.leave, this);
10648 toggle : function () {
10649 this.hoverState == 'in' ? this.leave() : this.enter();
10652 enter : function () {
10655 clearTimeout(this.timeout);
10657 this.hoverState = 'in'
10659 if (!this.delay || !this.delay.show) {
10664 this.timeout = setTimeout(function () {
10665 if (_t.hoverState == 'in') {
10668 }, this.delay.show)
10670 leave : function() {
10671 clearTimeout(this.timeout);
10673 this.hoverState = 'out'
10675 if (!this.delay || !this.delay.hide) {
10680 this.timeout = setTimeout(function () {
10681 if (_t.hoverState == 'out') {
10684 }, this.delay.hide)
10687 show : function (on_el)
10690 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
10693 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
10694 if (this.html !== false) {
10695 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
10697 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
10698 if (!this.title.length) {
10699 this.el.select('.popover-title',true).hide();
10702 var placement = typeof this.placement == 'function' ?
10703 this.placement.call(this, this.el, on_el) :
10706 var autoToken = /\s?auto?\s?/i;
10707 var autoPlace = autoToken.test(placement);
10709 placement = placement.replace(autoToken, '') || 'top';
10713 //this.el.setXY([0,0]);
10715 this.el.dom.style.display='block';
10716 this.el.addClass(placement);
10718 //this.el.appendTo(on_el);
10720 var p = this.getPosition();
10721 var box = this.el.getBox();
10726 var align = Roo.bootstrap.Popover.alignment[placement]
10727 this.el.alignTo(on_el, align[0],align[1]);
10728 //var arrow = this.el.select('.arrow',true).first();
10729 //arrow.set(align[2],
10731 this.el.addClass('in');
10732 this.hoverState = null;
10734 if (this.el.hasClass('fade')) {
10741 this.el.setXY([0,0]);
10742 this.el.removeClass('in');
10749 Roo.bootstrap.Popover.alignment = {
10750 'left' : ['r-l', [-10,0], 'right'],
10751 'right' : ['l-r', [10,0], 'left'],
10752 'bottom' : ['t-b', [0,10], 'top'],
10753 'top' : [ 'b-t', [0,-10], 'bottom']
10764 * @class Roo.bootstrap.Progress
10765 * @extends Roo.bootstrap.Component
10766 * Bootstrap Progress class
10767 * @cfg {Boolean} striped striped of the progress bar
10768 * @cfg {Boolean} active animated of the progress bar
10772 * Create a new Progress
10773 * @param {Object} config The config object
10776 Roo.bootstrap.Progress = function(config){
10777 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
10780 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
10785 getAutoCreate : function(){
10793 cfg.cls += ' progress-striped';
10797 cfg.cls += ' active';
10816 * @class Roo.bootstrap.ProgressBar
10817 * @extends Roo.bootstrap.Component
10818 * Bootstrap ProgressBar class
10819 * @cfg {Number} aria_valuenow aria-value now
10820 * @cfg {Number} aria_valuemin aria-value min
10821 * @cfg {Number} aria_valuemax aria-value max
10822 * @cfg {String} label label for the progress bar
10823 * @cfg {String} panel (success | info | warning | danger )
10824 * @cfg {String} role role of the progress bar
10825 * @cfg {String} sr_only text
10829 * Create a new ProgressBar
10830 * @param {Object} config The config object
10833 Roo.bootstrap.ProgressBar = function(config){
10834 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
10837 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
10841 aria_valuemax : 100,
10847 getAutoCreate : function()
10852 cls: 'progress-bar',
10853 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
10865 cfg.role = this.role;
10868 if(this.aria_valuenow){
10869 cfg['aria-valuenow'] = this.aria_valuenow;
10872 if(this.aria_valuemin){
10873 cfg['aria-valuemin'] = this.aria_valuemin;
10876 if(this.aria_valuemax){
10877 cfg['aria-valuemax'] = this.aria_valuemax;
10880 if(this.label && !this.sr_only){
10881 cfg.html = this.label;
10885 cfg.cls += ' progress-bar-' + this.panel;
10891 update : function(aria_valuenow)
10893 this.aria_valuenow = aria_valuenow;
10895 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
10910 * @class Roo.bootstrap.TabPanel
10911 * @extends Roo.bootstrap.Component
10912 * Bootstrap TabPanel class
10913 * @cfg {Boolean} active panel active
10914 * @cfg {String} html panel content
10915 * @cfg {String} tabId tab relate id
10919 * Create a new TabPanel
10920 * @param {Object} config The config object
10923 Roo.bootstrap.TabPanel = function(config){
10924 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
10927 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
10933 getAutoCreate : function(){
10937 html: this.html || ''
10941 cfg.cls += ' active';
10945 cfg.tabId = this.tabId;
10963 * @class Roo.bootstrap.DateField
10964 * @extends Roo.bootstrap.Input
10965 * Bootstrap DateField class
10966 * @cfg {Number} weekStart default 0
10967 * @cfg {Number} weekStart default 0
10968 * @cfg {Number} viewMode default empty, (months|years)
10969 * @cfg {Number} minViewMode default empty, (months|years)
10970 * @cfg {Number} startDate default -Infinity
10971 * @cfg {Number} endDate default Infinity
10972 * @cfg {Boolean} todayHighlight default false
10973 * @cfg {Boolean} todayBtn default false
10974 * @cfg {Boolean} calendarWeeks default false
10975 * @cfg {Object} daysOfWeekDisabled default empty
10977 * @cfg {Boolean} keyboardNavigation default true
10978 * @cfg {String} language default en
10981 * Create a new DateField
10982 * @param {Object} config The config object
10985 Roo.bootstrap.DateField = function(config){
10986 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
10990 * Fires when this field show.
10991 * @param {Roo.bootstrap.DateField} this
10992 * @param {Mixed} date The date value
10997 * Fires when this field hide.
10998 * @param {Roo.bootstrap.DateField} this
10999 * @param {Mixed} date The date value
11004 * Fires when select a date.
11005 * @param {Roo.bootstrap.DateField} this
11006 * @param {Mixed} date The date value
11012 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
11015 * @cfg {String} format
11016 * The default date format string which can be overriden for localization support. The format must be
11017 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
11021 * @cfg {String} altFormats
11022 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
11023 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
11025 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
11033 todayHighlight : false,
11039 keyboardNavigation: true,
11041 calendarWeeks: false,
11043 startDate: -Infinity,
11047 daysOfWeekDisabled: [],
11051 UTCDate: function()
11053 return new Date(Date.UTC.apply(Date, arguments));
11056 UTCToday: function()
11058 var today = new Date();
11059 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
11062 getDate: function() {
11063 var d = this.getUTCDate();
11064 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
11067 getUTCDate: function() {
11071 setDate: function(d) {
11072 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
11075 setUTCDate: function(d) {
11077 this.setValue(this.formatDate(this.date));
11080 onRender: function(ct, position)
11083 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
11085 this.language = this.language || 'en';
11086 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
11087 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
11089 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
11090 this.format = this.format || 'm/d/y';
11091 this.isInline = false;
11092 this.isInput = true;
11093 this.component = this.el.select('.add-on', true).first() || false;
11094 this.component = (this.component && this.component.length === 0) ? false : this.component;
11095 this.hasInput = this.component && this.inputEL().length;
11097 if (typeof(this.minViewMode === 'string')) {
11098 switch (this.minViewMode) {
11100 this.minViewMode = 1;
11103 this.minViewMode = 2;
11106 this.minViewMode = 0;
11111 if (typeof(this.viewMode === 'string')) {
11112 switch (this.viewMode) {
11125 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
11127 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
11129 this.picker().on('mousedown', this.onMousedown, this);
11130 this.picker().on('click', this.onClick, this);
11132 this.picker().addClass('datepicker-dropdown');
11134 this.startViewMode = this.viewMode;
11137 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
11138 if(!this.calendarWeeks){
11143 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
11144 v.attr('colspan', function(i, val){
11145 return parseInt(val) + 1;
11150 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
11152 this.setStartDate(this.startDate);
11153 this.setEndDate(this.endDate);
11155 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
11162 if(this.isInline) {
11167 picker : function()
11169 return this.el.select('.datepicker', true).first();
11172 fillDow: function()
11174 var dowCnt = this.weekStart;
11183 if(this.calendarWeeks){
11191 while (dowCnt < this.weekStart + 7) {
11195 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
11199 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
11202 fillMonths: function()
11205 var months = this.picker().select('>.datepicker-months td', true).first();
11207 months.dom.innerHTML = '';
11213 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
11216 months.createChild(month);
11221 update: function(){
11223 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
11225 if (this.date < this.startDate) {
11226 this.viewDate = new Date(this.startDate);
11227 } else if (this.date > this.endDate) {
11228 this.viewDate = new Date(this.endDate);
11230 this.viewDate = new Date(this.date);
11237 var d = new Date(this.viewDate),
11238 year = d.getUTCFullYear(),
11239 month = d.getUTCMonth(),
11240 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
11241 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
11242 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
11243 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
11244 currentDate = this.date && this.date.valueOf(),
11245 today = this.UTCToday();
11247 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
11249 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
11251 // this.picker.select('>tfoot th.today').
11252 // .text(dates[this.language].today)
11253 // .toggle(this.todayBtn !== false);
11255 this.updateNavArrows();
11258 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
11260 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
11262 prevMonth.setUTCDate(day);
11264 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
11266 var nextMonth = new Date(prevMonth);
11268 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
11270 nextMonth = nextMonth.valueOf();
11272 var fillMonths = false;
11274 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
11276 while(prevMonth.valueOf() < nextMonth) {
11279 if (prevMonth.getUTCDay() === this.weekStart) {
11281 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
11289 if(this.calendarWeeks){
11290 // ISO 8601: First week contains first thursday.
11291 // ISO also states week starts on Monday, but we can be more abstract here.
11293 // Start of current week: based on weekstart/current date
11294 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
11295 // Thursday of this week
11296 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
11297 // First Thursday of year, year from thursday
11298 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
11299 // Calendar week: ms between thursdays, div ms per day, div 7 days
11300 calWeek = (th - yth) / 864e5 / 7 + 1;
11302 fillMonths.cn.push({
11310 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
11312 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
11315 if (this.todayHighlight &&
11316 prevMonth.getUTCFullYear() == today.getFullYear() &&
11317 prevMonth.getUTCMonth() == today.getMonth() &&
11318 prevMonth.getUTCDate() == today.getDate()) {
11319 clsName += ' today';
11322 if (currentDate && prevMonth.valueOf() === currentDate) {
11323 clsName += ' active';
11326 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
11327 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
11328 clsName += ' disabled';
11331 fillMonths.cn.push({
11333 cls: 'day ' + clsName,
11334 html: prevMonth.getDate()
11337 prevMonth.setDate(prevMonth.getDate()+1);
11340 var currentYear = this.date && this.date.getUTCFullYear();
11341 var currentMonth = this.date && this.date.getUTCMonth();
11343 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
11345 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
11346 v.removeClass('active');
11348 if(currentYear === year && k === currentMonth){
11349 v.addClass('active');
11352 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
11353 v.addClass('disabled');
11359 year = parseInt(year/10, 10) * 10;
11361 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
11363 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
11366 for (var i = -1; i < 11; i++) {
11367 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
11369 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
11377 showMode: function(dir) {
11379 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
11381 Roo.each(this.picker().select('>div',true).elements, function(v){
11382 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
11385 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
11390 if(this.isInline) return;
11392 this.picker().removeClass(['bottom', 'top']);
11394 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
11396 * place to the top of element!
11400 this.picker().addClass('top');
11401 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
11406 this.picker().addClass('bottom');
11408 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
11411 parseDate : function(value){
11412 if(!value || value instanceof Date){
11415 var v = Date.parseDate(value, this.format);
11416 if (!v && this.useIso) {
11417 v = Date.parseDate(value, 'Y-m-d');
11419 if(!v && this.altFormats){
11420 if(!this.altFormatsArray){
11421 this.altFormatsArray = this.altFormats.split("|");
11423 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
11424 v = Date.parseDate(value, this.altFormatsArray[i]);
11430 formatDate : function(date, fmt){
11431 return (!date || !(date instanceof Date)) ?
11432 date : date.dateFormat(fmt || this.format);
11435 onFocus : function()
11437 Roo.bootstrap.DateField.superclass.onFocus.call(this);
11441 onBlur : function()
11443 Roo.bootstrap.DateField.superclass.onBlur.call(this);
11449 this.picker().show();
11453 this.fireEvent('show', this, this.date);
11458 if(this.isInline) return;
11459 this.picker().hide();
11460 this.viewMode = this.startViewMode;
11463 this.fireEvent('hide', this, this.date);
11467 onMousedown: function(e){
11468 e.stopPropagation();
11469 e.preventDefault();
11472 keyup: function(e){
11473 Roo.bootstrap.DateField.superclass.keyup.call(this);
11478 setValue: function(v){
11479 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
11481 this.fireEvent('select', this, this.date);
11485 fireKey: function(e){
11486 if (!this.picker().isVisible()){
11487 if (e.keyCode == 27) // allow escape to hide and re-show picker
11491 var dateChanged = false,
11493 newDate, newViewDate;
11497 e.preventDefault();
11501 if (!this.keyboardNavigation) break;
11502 dir = e.keyCode == 37 ? -1 : 1;
11505 newDate = this.moveYear(this.date, dir);
11506 newViewDate = this.moveYear(this.viewDate, dir);
11507 } else if (e.shiftKey){
11508 newDate = this.moveMonth(this.date, dir);
11509 newViewDate = this.moveMonth(this.viewDate, dir);
11511 newDate = new Date(this.date);
11512 newDate.setUTCDate(this.date.getUTCDate() + dir);
11513 newViewDate = new Date(this.viewDate);
11514 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
11516 if (this.dateWithinRange(newDate)){
11517 this.date = newDate;
11518 this.viewDate = newViewDate;
11519 this.setValue(this.formatDate(this.date));
11521 e.preventDefault();
11522 dateChanged = true;
11527 if (!this.keyboardNavigation) break;
11528 dir = e.keyCode == 38 ? -1 : 1;
11530 newDate = this.moveYear(this.date, dir);
11531 newViewDate = this.moveYear(this.viewDate, dir);
11532 } else if (e.shiftKey){
11533 newDate = this.moveMonth(this.date, dir);
11534 newViewDate = this.moveMonth(this.viewDate, dir);
11536 newDate = new Date(this.date);
11537 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
11538 newViewDate = new Date(this.viewDate);
11539 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
11541 if (this.dateWithinRange(newDate)){
11542 this.date = newDate;
11543 this.viewDate = newViewDate;
11544 this.setValue(this.formatDate(this.date));
11546 e.preventDefault();
11547 dateChanged = true;
11551 this.setValue(this.formatDate(this.date));
11553 e.preventDefault();
11556 this.setValue(this.formatDate(this.date));
11563 onClick: function(e) {
11564 e.stopPropagation();
11565 e.preventDefault();
11567 var target = e.getTarget();
11569 if(target.nodeName.toLowerCase() === 'i'){
11570 target = Roo.get(target).dom.parentNode;
11573 var nodeName = target.nodeName;
11574 var className = target.className;
11575 var html = target.innerHTML;
11577 switch(nodeName.toLowerCase()) {
11579 switch(className) {
11585 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
11586 switch(this.viewMode){
11588 this.viewDate = this.moveMonth(this.viewDate, dir);
11592 this.viewDate = this.moveYear(this.viewDate, dir);
11598 var date = new Date();
11599 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
11601 this.setValue(this.formatDate(this.date));
11607 if (className.indexOf('disabled') === -1) {
11608 this.viewDate.setUTCDate(1);
11609 if (className.indexOf('month') !== -1) {
11610 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
11612 var year = parseInt(html, 10) || 0;
11613 this.viewDate.setUTCFullYear(year);
11622 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
11623 var day = parseInt(html, 10) || 1;
11624 var year = this.viewDate.getUTCFullYear(),
11625 month = this.viewDate.getUTCMonth();
11627 if (className.indexOf('old') !== -1) {
11634 } else if (className.indexOf('new') !== -1) {
11642 this.date = this.UTCDate(year, month, day,0,0,0,0);
11643 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
11645 this.setValue(this.formatDate(this.date));
11652 setStartDate: function(startDate){
11653 this.startDate = startDate || -Infinity;
11654 if (this.startDate !== -Infinity) {
11655 this.startDate = this.parseDate(this.startDate);
11658 this.updateNavArrows();
11661 setEndDate: function(endDate){
11662 this.endDate = endDate || Infinity;
11663 if (this.endDate !== Infinity) {
11664 this.endDate = this.parseDate(this.endDate);
11667 this.updateNavArrows();
11670 setDaysOfWeekDisabled: function(daysOfWeekDisabled){
11671 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
11672 if (typeof(this.daysOfWeekDisabled) !== 'object') {
11673 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
11675 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
11676 return parseInt(d, 10);
11679 this.updateNavArrows();
11682 updateNavArrows: function() {
11683 var d = new Date(this.viewDate),
11684 year = d.getUTCFullYear(),
11685 month = d.getUTCMonth();
11687 Roo.each(this.picker().select('.prev', true).elements, function(v){
11689 switch (this.viewMode) {
11692 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
11698 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
11705 Roo.each(this.picker().select('.next', true).elements, function(v){
11707 switch (this.viewMode) {
11710 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
11716 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
11724 moveMonth: function(date, dir){
11725 if (!dir) return date;
11726 var new_date = new Date(date.valueOf()),
11727 day = new_date.getUTCDate(),
11728 month = new_date.getUTCMonth(),
11729 mag = Math.abs(dir),
11731 dir = dir > 0 ? 1 : -1;
11734 // If going back one month, make sure month is not current month
11735 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
11737 return new_date.getUTCMonth() == month;
11739 // If going forward one month, make sure month is as expected
11740 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
11742 return new_date.getUTCMonth() != new_month;
11744 new_month = month + dir;
11745 new_date.setUTCMonth(new_month);
11746 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
11747 if (new_month < 0 || new_month > 11)
11748 new_month = (new_month + 12) % 12;
11750 // For magnitudes >1, move one month at a time...
11751 for (var i=0; i<mag; i++)
11752 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
11753 new_date = this.moveMonth(new_date, dir);
11754 // ...then reset the day, keeping it in the new month
11755 new_month = new_date.getUTCMonth();
11756 new_date.setUTCDate(day);
11758 return new_month != new_date.getUTCMonth();
11761 // Common date-resetting loop -- if date is beyond end of month, make it
11764 new_date.setUTCDate(--day);
11765 new_date.setUTCMonth(new_month);
11770 moveYear: function(date, dir){
11771 return this.moveMonth(date, dir*12);
11774 dateWithinRange: function(date){
11775 return date >= this.startDate && date <= this.endDate;
11779 remove: function() {
11780 this.picker().remove();
11785 Roo.apply(Roo.bootstrap.DateField, {
11796 html: '<i class="icon-arrow-left"/>'
11806 html: '<i class="icon-arrow-right"/>'
11848 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
11849 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
11850 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
11851 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
11852 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
11865 navFnc: 'FullYear',
11870 navFnc: 'FullYear',
11875 Roo.apply(Roo.bootstrap.DateField, {
11879 cls: 'datepicker dropdown-menu',
11883 cls: 'datepicker-days',
11887 cls: 'table-condensed',
11889 Roo.bootstrap.DateField.head,
11893 Roo.bootstrap.DateField.footer
11900 cls: 'datepicker-months',
11904 cls: 'table-condensed',
11906 Roo.bootstrap.DateField.head,
11907 Roo.bootstrap.DateField.content,
11908 Roo.bootstrap.DateField.footer
11915 cls: 'datepicker-years',
11919 cls: 'table-condensed',
11921 Roo.bootstrap.DateField.head,
11922 Roo.bootstrap.DateField.content,
11923 Roo.bootstrap.DateField.footer
11942 * @class Roo.bootstrap.TimeField
11943 * @extends Roo.bootstrap.Input
11944 * Bootstrap DateField class
11948 * Create a new TimeField
11949 * @param {Object} config The config object
11952 Roo.bootstrap.TimeField = function(config){
11953 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
11957 * Fires when this field show.
11958 * @param {Roo.bootstrap.DateField} this
11959 * @param {Mixed} date The date value
11964 * Fires when this field hide.
11965 * @param {Roo.bootstrap.DateField} this
11966 * @param {Mixed} date The date value
11971 * Fires when select a date.
11972 * @param {Roo.bootstrap.DateField} this
11973 * @param {Mixed} date The date value
11979 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
11982 * @cfg {String} format
11983 * The default time format string which can be overriden for localization support. The format must be
11984 * valid according to {@link Date#parseDate} (defaults to 'H:i').
11988 onRender: function(ct, position)
11991 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
11993 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
11995 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
11997 this.pop = this.picker().select('>.datepicker-time',true).first();
11998 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
12000 this.picker().on('mousedown', this.onMousedown, this);
12001 this.picker().on('click', this.onClick, this);
12003 this.picker().addClass('datepicker-dropdown');
12008 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
12009 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
12010 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
12011 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
12012 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
12013 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
12017 fireKey: function(e){
12018 if (!this.picker().isVisible()){
12019 if (e.keyCode == 27) // allow escape to hide and re-show picker
12024 e.preventDefault();
12032 this.onTogglePeriod();
12035 this.onIncrementMinutes();
12038 this.onDecrementMinutes();
12047 onClick: function(e) {
12048 e.stopPropagation();
12049 e.preventDefault();
12052 picker : function()
12054 return this.el.select('.datepicker', true).first();
12057 fillTime: function()
12059 var time = this.pop.select('tbody', true).first();
12061 time.dom.innerHTML = '';
12076 cls: 'hours-up glyphicon glyphicon-chevron-up'
12096 cls: 'minutes-up glyphicon glyphicon-chevron-up'
12117 cls: 'timepicker-hour',
12132 cls: 'timepicker-minute',
12147 cls: 'btn btn-primary period',
12169 cls: 'hours-down glyphicon glyphicon-chevron-down'
12189 cls: 'minutes-down glyphicon glyphicon-chevron-down'
12207 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
12214 var hours = this.time.getHours();
12215 var minutes = this.time.getMinutes();
12228 hours = hours - 12;
12232 hours = '0' + hours;
12236 minutes = '0' + minutes;
12239 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
12240 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
12241 this.pop.select('button', true).first().dom.innerHTML = period;
12247 this.picker().removeClass(['bottom', 'top']);
12249 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
12251 * place to the top of element!
12255 this.picker().addClass('top');
12256 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12261 this.picker().addClass('bottom');
12263 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12266 onFocus : function()
12268 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
12272 onBlur : function()
12274 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
12280 this.picker().show();
12285 this.fireEvent('show', this, this.date);
12290 this.picker().hide();
12293 this.fireEvent('hide', this, this.date);
12296 setTime : function()
12299 this.setValue(this.time.format(this.format));
12301 this.fireEvent('select', this, this.date);
12306 onMousedown: function(e){
12307 e.stopPropagation();
12308 e.preventDefault();
12311 onIncrementHours: function()
12313 Roo.log('onIncrementHours');
12314 this.time = this.time.add(Date.HOUR, 1);
12319 onDecrementHours: function()
12321 Roo.log('onDecrementHours');
12322 this.time = this.time.add(Date.HOUR, -1);
12326 onIncrementMinutes: function()
12328 Roo.log('onIncrementMinutes');
12329 this.time = this.time.add(Date.MINUTE, 1);
12333 onDecrementMinutes: function()
12335 Roo.log('onDecrementMinutes');
12336 this.time = this.time.add(Date.MINUTE, -1);
12340 onTogglePeriod: function()
12342 Roo.log('onTogglePeriod');
12343 this.time = this.time.add(Date.HOUR, 12);
12350 Roo.apply(Roo.bootstrap.TimeField, {
12380 cls: 'btn btn-info ok',
12392 Roo.apply(Roo.bootstrap.TimeField, {
12396 cls: 'datepicker dropdown-menu',
12400 cls: 'datepicker-time',
12404 cls: 'table-condensed',
12406 Roo.bootstrap.TimeField.content,
12407 Roo.bootstrap.TimeField.footer
12426 * @class Roo.bootstrap.CheckBox
12427 * @extends Roo.bootstrap.Input
12428 * Bootstrap CheckBox class
12430 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
12431 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
12432 * @cfg {String} boxLabel The text that appears beside the checkbox
12433 * @cfg {Boolean} checked initnal the element
12436 * Create a new CheckBox
12437 * @param {Object} config The config object
12440 Roo.bootstrap.CheckBox = function(config){
12441 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
12446 * Fires when the element is checked or unchecked.
12447 * @param {Roo.bootstrap.CheckBox} this This input
12448 * @param {Boolean} checked The new checked value
12454 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
12456 inputType: 'checkbox',
12462 getAutoCreate : function()
12464 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
12470 cfg.cls = 'form-group' //input-group
12475 type : this.inputType,
12476 value : (!this.checked) ? this.valueOff : this.inputValue,
12478 placeholder : this.placeholder || ''
12482 if (this.disabled) {
12483 input.disabled=true;
12487 input.checked = this.checked;
12491 input.name = this.name;
12495 input.cls += ' input-' + this.size;
12499 ['xs','sm','md','lg'].map(function(size){
12500 if (settings[size]) {
12501 cfg.cls += ' col-' + size + '-' + settings[size];
12505 var inputblock = input;
12507 if (this.before || this.after) {
12510 cls : 'input-group',
12514 inputblock.cn.push({
12516 cls : 'input-group-addon',
12520 inputblock.cn.push(input);
12522 inputblock.cn.push({
12524 cls : 'input-group-addon',
12531 if (align ==='left' && this.fieldLabel.length) {
12532 Roo.log("left and has label");
12538 cls : 'control-label col-md-' + this.labelWidth,
12539 html : this.fieldLabel
12543 cls : "col-md-" + (12 - this.labelWidth),
12550 } else if ( this.fieldLabel.length) {
12555 tag: this.boxLabel ? 'span' : 'label',
12557 cls: 'control-label box-input-label',
12558 //cls : 'input-group-addon',
12559 html : this.fieldLabel
12569 Roo.log(" no label && no align");
12584 html: this.boxLabel
12593 * return the real input element.
12595 inputEl: function ()
12597 return this.el.select('input.form-box',true).first();
12600 initEvents : function()
12602 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
12604 this.inputEl().on('click', this.onClick, this);
12608 onClick : function()
12610 this.setChecked(!this.checked);
12613 setChecked : function(state,suppressEvent)
12615 this.checked = state;
12617 this.inputEl().dom.checked = state;
12619 if(suppressEvent !== true){
12620 this.fireEvent('check', this, state);
12623 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
12627 setValue : function(v,suppressEvent)
12629 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
12643 * @class Roo.bootstrap.Radio
12644 * @extends Roo.bootstrap.CheckBox
12645 * Bootstrap Radio class
12648 * Create a new Radio
12649 * @param {Object} config The config object
12652 Roo.bootstrap.Radio = function(config){
12653 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
12657 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
12659 inputType: 'radio',
12663 getAutoCreate : function()
12665 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
12671 cfg.cls = 'form-group' //input-group
12676 type : this.inputType,
12677 value : (!this.checked) ? this.valueOff : this.inputValue,
12679 placeholder : this.placeholder || ''
12683 if (this.disabled) {
12684 input.disabled=true;
12688 input.checked = this.checked;
12692 input.name = this.name;
12696 input.cls += ' input-' + this.size;
12700 ['xs','sm','md','lg'].map(function(size){
12701 if (settings[size]) {
12702 cfg.cls += ' col-' + size + '-' + settings[size];
12706 var inputblock = input;
12708 if (this.before || this.after) {
12711 cls : 'input-group',
12715 inputblock.cn.push({
12717 cls : 'input-group-addon',
12721 inputblock.cn.push(input);
12723 inputblock.cn.push({
12725 cls : 'input-group-addon',
12732 if (align ==='left' && this.fieldLabel.length) {
12733 Roo.log("left and has label");
12739 cls : 'control-label col-md-' + this.labelWidth,
12740 html : this.fieldLabel
12744 cls : "col-md-" + (12 - this.labelWidth),
12751 } else if ( this.fieldLabel.length) {
12758 cls: 'control-label box-input-label',
12759 //cls : 'input-group-addon',
12760 html : this.fieldLabel
12770 Roo.log(" no label && no align");
12785 html: this.boxLabel
12793 onClick : function()
12795 this.setChecked(true);
12798 setChecked : function(state,suppressEvent)
12801 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
12802 v.dom.checked = false;
12806 this.checked = state;
12807 this.inputEl().dom.checked = state;
12809 if(suppressEvent !== true){
12810 this.fireEvent('check', this, state);
12813 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
12817 getGroupValue : function()
12820 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
12821 if(v.dom.checked == true){
12822 value = v.dom.value;
12830 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
12831 * @return {Mixed} value The field value
12833 getValue : function(){
12834 return this.getGroupValue();
12840 //<script type="text/javascript">
12843 * Based Ext JS Library 1.1.1
12844 * Copyright(c) 2006-2007, Ext JS, LLC.
12850 * @class Roo.HtmlEditorCore
12851 * @extends Roo.Component
12852 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
12854 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
12857 Roo.HtmlEditorCore = function(config){
12860 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
12863 * @event initialize
12864 * Fires when the editor is fully initialized (including the iframe)
12865 * @param {Roo.HtmlEditorCore} this
12870 * Fires when the editor is first receives the focus. Any insertion must wait
12871 * until after this event.
12872 * @param {Roo.HtmlEditorCore} this
12876 * @event beforesync
12877 * Fires before the textarea is updated with content from the editor iframe. Return false
12878 * to cancel the sync.
12879 * @param {Roo.HtmlEditorCore} this
12880 * @param {String} html
12884 * @event beforepush
12885 * Fires before the iframe editor is updated with content from the textarea. Return false
12886 * to cancel the push.
12887 * @param {Roo.HtmlEditorCore} this
12888 * @param {String} html
12893 * Fires when the textarea is updated with content from the editor iframe.
12894 * @param {Roo.HtmlEditorCore} this
12895 * @param {String} html
12900 * Fires when the iframe editor is updated with content from the textarea.
12901 * @param {Roo.HtmlEditorCore} this
12902 * @param {String} html
12907 * @event editorevent
12908 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
12909 * @param {Roo.HtmlEditorCore} this
12917 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
12921 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
12927 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
12932 * @cfg {Number} height (in pixels)
12936 * @cfg {Number} width (in pixels)
12941 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
12944 stylesheets: false,
12949 // private properties
12950 validationEvent : false,
12952 initialized : false,
12954 sourceEditMode : false,
12955 onFocus : Roo.emptyFn,
12957 hideMode:'offsets',
12965 * Protected method that will not generally be called directly. It
12966 * is called when the editor initializes the iframe with HTML contents. Override this method if you
12967 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
12969 getDocMarkup : function(){
12972 Roo.log(this.stylesheets);
12974 // inherit styels from page...??
12975 if (this.stylesheets === false) {
12977 Roo.get(document.head).select('style').each(function(node) {
12978 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
12981 Roo.get(document.head).select('link').each(function(node) {
12982 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
12985 } else if (!this.stylesheets.length) {
12987 st = '<style type="text/css">' +
12988 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
12991 Roo.each(this.stylesheets, function(s) {
12992 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
12997 st += '<style type="text/css">' +
12998 'IMG { cursor: pointer } ' +
13002 return '<html><head>' + st +
13003 //<style type="text/css">' +
13004 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
13006 ' </head><body class="roo-htmleditor-body"></body></html>';
13010 onRender : function(ct, position)
13013 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
13014 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
13017 this.el.dom.style.border = '0 none';
13018 this.el.dom.setAttribute('tabIndex', -1);
13019 this.el.addClass('x-hidden hide');
13023 if(Roo.isIE){ // fix IE 1px bogus margin
13024 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
13028 this.frameId = Roo.id();
13032 var iframe = this.owner.wrap.createChild({
13034 cls: 'form-control', // bootstrap..
13036 name: this.frameId,
13037 frameBorder : 'no',
13038 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
13043 this.iframe = iframe.dom;
13045 this.assignDocWin();
13047 this.doc.designMode = 'on';
13050 this.doc.write(this.getDocMarkup());
13054 var task = { // must defer to wait for browser to be ready
13056 //console.log("run task?" + this.doc.readyState);
13057 this.assignDocWin();
13058 if(this.doc.body || this.doc.readyState == 'complete'){
13060 this.doc.designMode="on";
13064 Roo.TaskMgr.stop(task);
13065 this.initEditor.defer(10, this);
13072 Roo.TaskMgr.start(task);
13079 onResize : function(w, h)
13081 Roo.log('resize: ' +w + ',' + h );
13082 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
13086 if(typeof w == 'number'){
13088 this.iframe.style.width = w + 'px';
13090 if(typeof h == 'number'){
13092 this.iframe.style.height = h + 'px';
13094 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
13101 * Toggles the editor between standard and source edit mode.
13102 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
13104 toggleSourceEdit : function(sourceEditMode){
13106 this.sourceEditMode = sourceEditMode === true;
13108 if(this.sourceEditMode){
13110 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
13113 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
13114 //this.iframe.className = '';
13117 //this.setSize(this.owner.wrap.getSize());
13118 //this.fireEvent('editmodechange', this, this.sourceEditMode);
13125 * Protected method that will not generally be called directly. If you need/want
13126 * custom HTML cleanup, this is the method you should override.
13127 * @param {String} html The HTML to be cleaned
13128 * return {String} The cleaned HTML
13130 cleanHtml : function(html){
13131 html = String(html);
13132 if(html.length > 5){
13133 if(Roo.isSafari){ // strip safari nonsense
13134 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
13137 if(html == ' '){
13144 * HTML Editor -> Textarea
13145 * Protected method that will not generally be called directly. Syncs the contents
13146 * of the editor iframe with the textarea.
13148 syncValue : function(){
13149 if(this.initialized){
13150 var bd = (this.doc.body || this.doc.documentElement);
13151 //this.cleanUpPaste(); -- this is done else where and causes havoc..
13152 var html = bd.innerHTML;
13154 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
13155 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
13157 html = '<div style="'+m[0]+'">' + html + '</div>';
13160 html = this.cleanHtml(html);
13161 // fix up the special chars.. normaly like back quotes in word...
13162 // however we do not want to do this with chinese..
13163 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
13164 var cc = b.charCodeAt();
13166 (cc >= 0x4E00 && cc < 0xA000 ) ||
13167 (cc >= 0x3400 && cc < 0x4E00 ) ||
13168 (cc >= 0xf900 && cc < 0xfb00 )
13174 if(this.owner.fireEvent('beforesync', this, html) !== false){
13175 this.el.dom.value = html;
13176 this.owner.fireEvent('sync', this, html);
13182 * Protected method that will not generally be called directly. Pushes the value of the textarea
13183 * into the iframe editor.
13185 pushValue : function(){
13186 if(this.initialized){
13187 var v = this.el.dom.value.trim();
13189 // if(v.length < 1){
13193 if(this.owner.fireEvent('beforepush', this, v) !== false){
13194 var d = (this.doc.body || this.doc.documentElement);
13196 this.cleanUpPaste();
13197 this.el.dom.value = d.innerHTML;
13198 this.owner.fireEvent('push', this, v);
13204 deferFocus : function(){
13205 this.focus.defer(10, this);
13209 focus : function(){
13210 if(this.win && !this.sourceEditMode){
13217 assignDocWin: function()
13219 var iframe = this.iframe;
13222 this.doc = iframe.contentWindow.document;
13223 this.win = iframe.contentWindow;
13225 if (!Roo.get(this.frameId)) {
13228 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
13229 this.win = Roo.get(this.frameId).dom.contentWindow;
13234 initEditor : function(){
13235 //console.log("INIT EDITOR");
13236 this.assignDocWin();
13240 this.doc.designMode="on";
13242 this.doc.write(this.getDocMarkup());
13245 var dbody = (this.doc.body || this.doc.documentElement);
13246 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
13247 // this copies styles from the containing element into thsi one..
13248 // not sure why we need all of this..
13249 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
13250 ss['background-attachment'] = 'fixed'; // w3c
13251 dbody.bgProperties = 'fixed'; // ie
13252 Roo.DomHelper.applyStyles(dbody, ss);
13253 Roo.EventManager.on(this.doc, {
13254 //'mousedown': this.onEditorEvent,
13255 'mouseup': this.onEditorEvent,
13256 'dblclick': this.onEditorEvent,
13257 'click': this.onEditorEvent,
13258 'keyup': this.onEditorEvent,
13263 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
13265 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
13266 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
13268 this.initialized = true;
13270 this.owner.fireEvent('initialize', this);
13275 onDestroy : function(){
13281 //for (var i =0; i < this.toolbars.length;i++) {
13282 // // fixme - ask toolbars for heights?
13283 // this.toolbars[i].onDestroy();
13286 //this.wrap.dom.innerHTML = '';
13287 //this.wrap.remove();
13292 onFirstFocus : function(){
13294 this.assignDocWin();
13297 this.activated = true;
13300 if(Roo.isGecko){ // prevent silly gecko errors
13302 var s = this.win.getSelection();
13303 if(!s.focusNode || s.focusNode.nodeType != 3){
13304 var r = s.getRangeAt(0);
13305 r.selectNodeContents((this.doc.body || this.doc.documentElement));
13310 this.execCmd('useCSS', true);
13311 this.execCmd('styleWithCSS', false);
13314 this.owner.fireEvent('activate', this);
13318 adjustFont: function(btn){
13319 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
13320 //if(Roo.isSafari){ // safari
13323 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
13324 if(Roo.isSafari){ // safari
13325 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
13326 v = (v < 10) ? 10 : v;
13327 v = (v > 48) ? 48 : v;
13328 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
13333 v = Math.max(1, v+adjust);
13335 this.execCmd('FontSize', v );
13338 onEditorEvent : function(e){
13339 this.owner.fireEvent('editorevent', this, e);
13340 // this.updateToolbar();
13341 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
13344 insertTag : function(tg)
13346 // could be a bit smarter... -> wrap the current selected tRoo..
13347 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
13349 range = this.createRange(this.getSelection());
13350 var wrappingNode = this.doc.createElement(tg.toLowerCase());
13351 wrappingNode.appendChild(range.extractContents());
13352 range.insertNode(wrappingNode);
13359 this.execCmd("formatblock", tg);
13363 insertText : function(txt)
13367 var range = this.createRange();
13368 range.deleteContents();
13369 //alert(Sender.getAttribute('label'));
13371 range.insertNode(this.doc.createTextNode(txt));
13377 * Executes a Midas editor command on the editor document and performs necessary focus and
13378 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
13379 * @param {String} cmd The Midas command
13380 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
13382 relayCmd : function(cmd, value){
13384 this.execCmd(cmd, value);
13385 this.owner.fireEvent('editorevent', this);
13386 //this.updateToolbar();
13387 this.owner.deferFocus();
13391 * Executes a Midas editor command directly on the editor document.
13392 * For visual commands, you should use {@link #relayCmd} instead.
13393 * <b>This should only be called after the editor is initialized.</b>
13394 * @param {String} cmd The Midas command
13395 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
13397 execCmd : function(cmd, value){
13398 this.doc.execCommand(cmd, false, value === undefined ? null : value);
13405 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
13407 * @param {String} text | dom node..
13409 insertAtCursor : function(text)
13414 if(!this.activated){
13420 var r = this.doc.selection.createRange();
13431 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
13435 // from jquery ui (MIT licenced)
13437 var win = this.win;
13439 if (win.getSelection && win.getSelection().getRangeAt) {
13440 range = win.getSelection().getRangeAt(0);
13441 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
13442 range.insertNode(node);
13443 } else if (win.document.selection && win.document.selection.createRange) {
13444 // no firefox support
13445 var txt = typeof(text) == 'string' ? text : text.outerHTML;
13446 win.document.selection.createRange().pasteHTML(txt);
13448 // no firefox support
13449 var txt = typeof(text) == 'string' ? text : text.outerHTML;
13450 this.execCmd('InsertHTML', txt);
13459 mozKeyPress : function(e){
13461 var c = e.getCharCode(), cmd;
13464 c = String.fromCharCode(c).toLowerCase();
13478 this.cleanUpPaste.defer(100, this);
13486 e.preventDefault();
13494 fixKeys : function(){ // load time branching for fastest keydown performance
13496 return function(e){
13497 var k = e.getKey(), r;
13500 r = this.doc.selection.createRange();
13503 r.pasteHTML('    ');
13510 r = this.doc.selection.createRange();
13512 var target = r.parentElement();
13513 if(!target || target.tagName.toLowerCase() != 'li'){
13515 r.pasteHTML('<br />');
13521 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
13522 this.cleanUpPaste.defer(100, this);
13528 }else if(Roo.isOpera){
13529 return function(e){
13530 var k = e.getKey();
13534 this.execCmd('InsertHTML','    ');
13537 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
13538 this.cleanUpPaste.defer(100, this);
13543 }else if(Roo.isSafari){
13544 return function(e){
13545 var k = e.getKey();
13549 this.execCmd('InsertText','\t');
13553 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
13554 this.cleanUpPaste.defer(100, this);
13562 getAllAncestors: function()
13564 var p = this.getSelectedNode();
13567 a.push(p); // push blank onto stack..
13568 p = this.getParentElement();
13572 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
13576 a.push(this.doc.body);
13580 lastSelNode : false,
13583 getSelection : function()
13585 this.assignDocWin();
13586 return Roo.isIE ? this.doc.selection : this.win.getSelection();
13589 getSelectedNode: function()
13591 // this may only work on Gecko!!!
13593 // should we cache this!!!!
13598 var range = this.createRange(this.getSelection()).cloneRange();
13601 var parent = range.parentElement();
13603 var testRange = range.duplicate();
13604 testRange.moveToElementText(parent);
13605 if (testRange.inRange(range)) {
13608 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
13611 parent = parent.parentElement;
13616 // is ancestor a text element.
13617 var ac = range.commonAncestorContainer;
13618 if (ac.nodeType == 3) {
13619 ac = ac.parentNode;
13622 var ar = ac.childNodes;
13625 var other_nodes = [];
13626 var has_other_nodes = false;
13627 for (var i=0;i<ar.length;i++) {
13628 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
13631 // fullly contained node.
13633 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
13638 // probably selected..
13639 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
13640 other_nodes.push(ar[i]);
13644 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
13649 has_other_nodes = true;
13651 if (!nodes.length && other_nodes.length) {
13652 nodes= other_nodes;
13654 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
13660 createRange: function(sel)
13662 // this has strange effects when using with
13663 // top toolbar - not sure if it's a great idea.
13664 //this.editor.contentWindow.focus();
13665 if (typeof sel != "undefined") {
13667 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
13669 return this.doc.createRange();
13672 return this.doc.createRange();
13675 getParentElement: function()
13678 this.assignDocWin();
13679 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
13681 var range = this.createRange(sel);
13684 var p = range.commonAncestorContainer;
13685 while (p.nodeType == 3) { // text node
13696 * Range intersection.. the hard stuff...
13700 * [ -- selected range --- ]
13704 * if end is before start or hits it. fail.
13705 * if start is after end or hits it fail.
13707 * if either hits (but other is outside. - then it's not
13713 // @see http://www.thismuchiknow.co.uk/?p=64.
13714 rangeIntersectsNode : function(range, node)
13716 var nodeRange = node.ownerDocument.createRange();
13718 nodeRange.selectNode(node);
13720 nodeRange.selectNodeContents(node);
13723 var rangeStartRange = range.cloneRange();
13724 rangeStartRange.collapse(true);
13726 var rangeEndRange = range.cloneRange();
13727 rangeEndRange.collapse(false);
13729 var nodeStartRange = nodeRange.cloneRange();
13730 nodeStartRange.collapse(true);
13732 var nodeEndRange = nodeRange.cloneRange();
13733 nodeEndRange.collapse(false);
13735 return rangeStartRange.compareBoundaryPoints(
13736 Range.START_TO_START, nodeEndRange) == -1 &&
13737 rangeEndRange.compareBoundaryPoints(
13738 Range.START_TO_START, nodeStartRange) == 1;
13742 rangeCompareNode : function(range, node)
13744 var nodeRange = node.ownerDocument.createRange();
13746 nodeRange.selectNode(node);
13748 nodeRange.selectNodeContents(node);
13752 range.collapse(true);
13754 nodeRange.collapse(true);
13756 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
13757 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
13759 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
13761 var nodeIsBefore = ss == 1;
13762 var nodeIsAfter = ee == -1;
13764 if (nodeIsBefore && nodeIsAfter)
13766 if (!nodeIsBefore && nodeIsAfter)
13767 return 1; //right trailed.
13769 if (nodeIsBefore && !nodeIsAfter)
13770 return 2; // left trailed.
13775 // private? - in a new class?
13776 cleanUpPaste : function()
13778 // cleans up the whole document..
13779 Roo.log('cleanuppaste');
13781 this.cleanUpChildren(this.doc.body);
13782 var clean = this.cleanWordChars(this.doc.body.innerHTML);
13783 if (clean != this.doc.body.innerHTML) {
13784 this.doc.body.innerHTML = clean;
13789 cleanWordChars : function(input) {// change the chars to hex code
13790 var he = Roo.HtmlEditorCore;
13792 var output = input;
13793 Roo.each(he.swapCodes, function(sw) {
13794 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
13796 output = output.replace(swapper, sw[1]);
13803 cleanUpChildren : function (n)
13805 if (!n.childNodes.length) {
13808 for (var i = n.childNodes.length-1; i > -1 ; i--) {
13809 this.cleanUpChild(n.childNodes[i]);
13816 cleanUpChild : function (node)
13819 //console.log(node);
13820 if (node.nodeName == "#text") {
13821 // clean up silly Windows -- stuff?
13824 if (node.nodeName == "#comment") {
13825 node.parentNode.removeChild(node);
13826 // clean up silly Windows -- stuff?
13830 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
13832 node.parentNode.removeChild(node);
13837 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
13839 // remove <a name=....> as rendering on yahoo mailer is borked with this.
13840 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
13842 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
13843 // remove_keep_children = true;
13846 if (remove_keep_children) {
13847 this.cleanUpChildren(node);
13848 // inserts everything just before this node...
13849 while (node.childNodes.length) {
13850 var cn = node.childNodes[0];
13851 node.removeChild(cn);
13852 node.parentNode.insertBefore(cn, node);
13854 node.parentNode.removeChild(node);
13858 if (!node.attributes || !node.attributes.length) {
13859 this.cleanUpChildren(node);
13863 function cleanAttr(n,v)
13866 if (v.match(/^\./) || v.match(/^\//)) {
13869 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
13872 if (v.match(/^#/)) {
13875 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
13876 node.removeAttribute(n);
13880 function cleanStyle(n,v)
13882 if (v.match(/expression/)) { //XSS?? should we even bother..
13883 node.removeAttribute(n);
13886 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
13887 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
13890 var parts = v.split(/;/);
13893 Roo.each(parts, function(p) {
13894 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
13898 var l = p.split(':').shift().replace(/\s+/g,'');
13899 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
13901 if ( cblack.indexOf(l) > -1) {
13902 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
13903 //node.removeAttribute(n);
13907 // only allow 'c whitelisted system attributes'
13908 if ( cwhite.length && cwhite.indexOf(l) < 0) {
13909 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
13910 //node.removeAttribute(n);
13920 if (clean.length) {
13921 node.setAttribute(n, clean.join(';'));
13923 node.removeAttribute(n);
13929 for (var i = node.attributes.length-1; i > -1 ; i--) {
13930 var a = node.attributes[i];
13933 if (a.name.toLowerCase().substr(0,2)=='on') {
13934 node.removeAttribute(a.name);
13937 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
13938 node.removeAttribute(a.name);
13941 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
13942 cleanAttr(a.name,a.value); // fixme..
13945 if (a.name == 'style') {
13946 cleanStyle(a.name,a.value);
13949 /// clean up MS crap..
13950 // tecnically this should be a list of valid class'es..
13953 if (a.name == 'class') {
13954 if (a.value.match(/^Mso/)) {
13955 node.className = '';
13958 if (a.value.match(/body/)) {
13959 node.className = '';
13970 this.cleanUpChildren(node);
13976 // hide stuff that is not compatible
13990 * @event specialkey
13994 * @cfg {String} fieldClass @hide
13997 * @cfg {String} focusClass @hide
14000 * @cfg {String} autoCreate @hide
14003 * @cfg {String} inputType @hide
14006 * @cfg {String} invalidClass @hide
14009 * @cfg {String} invalidText @hide
14012 * @cfg {String} msgFx @hide
14015 * @cfg {String} validateOnBlur @hide
14019 Roo.HtmlEditorCore.white = [
14020 'area', 'br', 'img', 'input', 'hr', 'wbr',
14022 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
14023 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
14024 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
14025 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
14026 'table', 'ul', 'xmp',
14028 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
14031 'dir', 'menu', 'ol', 'ul', 'dl',
14037 Roo.HtmlEditorCore.black = [
14038 // 'embed', 'object', // enable - backend responsiblity to clean thiese
14040 'base', 'basefont', 'bgsound', 'blink', 'body',
14041 'frame', 'frameset', 'head', 'html', 'ilayer',
14042 'iframe', 'layer', 'link', 'meta', 'object',
14043 'script', 'style' ,'title', 'xml' // clean later..
14045 Roo.HtmlEditorCore.clean = [
14046 'script', 'style', 'title', 'xml'
14048 Roo.HtmlEditorCore.remove = [
14053 Roo.HtmlEditorCore.ablack = [
14057 Roo.HtmlEditorCore.aclean = [
14058 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
14062 Roo.HtmlEditorCore.pwhite= [
14063 'http', 'https', 'mailto'
14066 // white listed style attributes.
14067 Roo.HtmlEditorCore.cwhite= [
14068 // 'text-align', /// default is to allow most things..
14074 // black listed style attributes.
14075 Roo.HtmlEditorCore.cblack= [
14076 // 'font-size' -- this can be set by the project
14080 Roo.HtmlEditorCore.swapCodes =[
14099 * @class Roo.bootstrap.HtmlEditor
14100 * @extends Roo.bootstrap.TextArea
14101 * Bootstrap HtmlEditor class
14104 * Create a new HtmlEditor
14105 * @param {Object} config The config object
14108 Roo.bootstrap.HtmlEditor = function(config){
14109 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
14110 if (!this.toolbars) {
14111 this.toolbars = [];
14113 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
14116 * @event initialize
14117 * Fires when the editor is fully initialized (including the iframe)
14118 * @param {HtmlEditor} this
14123 * Fires when the editor is first receives the focus. Any insertion must wait
14124 * until after this event.
14125 * @param {HtmlEditor} this
14129 * @event beforesync
14130 * Fires before the textarea is updated with content from the editor iframe. Return false
14131 * to cancel the sync.
14132 * @param {HtmlEditor} this
14133 * @param {String} html
14137 * @event beforepush
14138 * Fires before the iframe editor is updated with content from the textarea. Return false
14139 * to cancel the push.
14140 * @param {HtmlEditor} this
14141 * @param {String} html
14146 * Fires when the textarea is updated with content from the editor iframe.
14147 * @param {HtmlEditor} this
14148 * @param {String} html
14153 * Fires when the iframe editor is updated with content from the textarea.
14154 * @param {HtmlEditor} this
14155 * @param {String} html
14159 * @event editmodechange
14160 * Fires when the editor switches edit modes
14161 * @param {HtmlEditor} this
14162 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
14164 editmodechange: true,
14166 * @event editorevent
14167 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
14168 * @param {HtmlEditor} this
14172 * @event firstfocus
14173 * Fires when on first focus - needed by toolbars..
14174 * @param {HtmlEditor} this
14179 * Auto save the htmlEditor value as a file into Events
14180 * @param {HtmlEditor} this
14184 * @event savedpreview
14185 * preview the saved version of htmlEditor
14186 * @param {HtmlEditor} this
14193 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
14197 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
14202 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
14207 * @cfg {Number} height (in pixels)
14211 * @cfg {Number} width (in pixels)
14216 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
14219 stylesheets: false,
14224 // private properties
14225 validationEvent : false,
14227 initialized : false,
14230 onFocus : Roo.emptyFn,
14232 hideMode:'offsets',
14235 tbContainer : false,
14237 toolbarContainer :function() {
14238 return this.wrap.select('.x-html-editor-tb',true).first();
14242 * Protected method that will not generally be called directly. It
14243 * is called when the editor creates its toolbar. Override this method if you need to
14244 * add custom toolbar buttons.
14245 * @param {HtmlEditor} editor
14247 createToolbar : function(){
14249 Roo.log("create toolbars");
14251 this.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard({editor: this} ) ];
14252 this.toolbars[0].render(this.toolbarContainer());
14256 // if (!editor.toolbars || !editor.toolbars.length) {
14257 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
14260 // for (var i =0 ; i < editor.toolbars.length;i++) {
14261 // editor.toolbars[i] = Roo.factory(
14262 // typeof(editor.toolbars[i]) == 'string' ?
14263 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
14264 // Roo.bootstrap.HtmlEditor);
14265 // editor.toolbars[i].init(editor);
14271 onRender : function(ct, position)
14273 // Roo.log("Call onRender: " + this.xtype);
14275 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
14277 this.wrap = this.inputEl().wrap({
14278 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
14281 this.editorcore.onRender(ct, position);
14283 if (this.resizable) {
14284 this.resizeEl = new Roo.Resizable(this.wrap, {
14288 minHeight : this.height,
14289 height: this.height,
14290 handles : this.resizable,
14293 resize : function(r, w, h) {
14294 _t.onResize(w,h); // -something
14300 this.createToolbar(this);
14303 if(!this.width && this.resizable){
14304 this.setSize(this.wrap.getSize());
14306 if (this.resizeEl) {
14307 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
14308 // should trigger onReize..
14314 onResize : function(w, h)
14316 Roo.log('resize: ' +w + ',' + h );
14317 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
14321 if(this.inputEl() ){
14322 if(typeof w == 'number'){
14323 var aw = w - this.wrap.getFrameWidth('lr');
14324 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
14327 if(typeof h == 'number'){
14328 var tbh = -11; // fixme it needs to tool bar size!
14329 for (var i =0; i < this.toolbars.length;i++) {
14330 // fixme - ask toolbars for heights?
14331 tbh += this.toolbars[i].el.getHeight();
14332 //if (this.toolbars[i].footer) {
14333 // tbh += this.toolbars[i].footer.el.getHeight();
14341 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
14342 ah -= 5; // knock a few pixes off for look..
14343 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
14347 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
14348 this.editorcore.onResize(ew,eh);
14353 * Toggles the editor between standard and source edit mode.
14354 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
14356 toggleSourceEdit : function(sourceEditMode)
14358 this.editorcore.toggleSourceEdit(sourceEditMode);
14360 if(this.editorcore.sourceEditMode){
14361 Roo.log('editor - showing textarea');
14364 // Roo.log(this.syncValue());
14366 this.inputEl().removeClass('hide');
14367 this.inputEl().dom.removeAttribute('tabIndex');
14368 this.inputEl().focus();
14370 Roo.log('editor - hiding textarea');
14372 // Roo.log(this.pushValue());
14375 this.inputEl().addClass('hide');
14376 this.inputEl().dom.setAttribute('tabIndex', -1);
14377 //this.deferFocus();
14380 if(this.resizable){
14381 this.setSize(this.wrap.getSize());
14384 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
14387 // private (for BoxComponent)
14388 adjustSize : Roo.BoxComponent.prototype.adjustSize,
14390 // private (for BoxComponent)
14391 getResizeEl : function(){
14395 // private (for BoxComponent)
14396 getPositionEl : function(){
14401 initEvents : function(){
14402 this.originalValue = this.getValue();
14406 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
14409 // markInvalid : Roo.emptyFn,
14411 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
14414 // clearInvalid : Roo.emptyFn,
14416 setValue : function(v){
14417 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
14418 this.editorcore.pushValue();
14423 deferFocus : function(){
14424 this.focus.defer(10, this);
14428 focus : function(){
14429 this.editorcore.focus();
14435 onDestroy : function(){
14441 for (var i =0; i < this.toolbars.length;i++) {
14442 // fixme - ask toolbars for heights?
14443 this.toolbars[i].onDestroy();
14446 this.wrap.dom.innerHTML = '';
14447 this.wrap.remove();
14452 onFirstFocus : function(){
14453 //Roo.log("onFirstFocus");
14454 this.editorcore.onFirstFocus();
14455 for (var i =0; i < this.toolbars.length;i++) {
14456 this.toolbars[i].onFirstFocus();
14462 syncValue : function()
14464 this.editorcore.syncValue();
14467 pushValue : function()
14469 this.editorcore.pushValue();
14473 // hide stuff that is not compatible
14487 * @event specialkey
14491 * @cfg {String} fieldClass @hide
14494 * @cfg {String} focusClass @hide
14497 * @cfg {String} autoCreate @hide
14500 * @cfg {String} inputType @hide
14503 * @cfg {String} invalidClass @hide
14506 * @cfg {String} invalidText @hide
14509 * @cfg {String} msgFx @hide
14512 * @cfg {String} validateOnBlur @hide
14523 * @class Roo.bootstrap.HtmlEditorToolbar1
14528 new Roo.bootstrap.HtmlEditor({
14531 new Roo.bootstrap.HtmlEditorToolbar1({
14532 disable : { fonts: 1 , format: 1, ..., ... , ...],
14538 * @cfg {Object} disable List of elements to disable..
14539 * @cfg {Array} btns List of additional buttons.
14543 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
14546 Roo.bootstrap.HtmlEditor.ToolbarStandard = function(config)
14549 Roo.apply(this, config);
14551 // default disabled, based on 'good practice'..
14552 this.disable = this.disable || {};
14553 Roo.applyIf(this.disable, {
14556 specialElements : true
14558 Roo.bootstrap.HtmlEditor.ToolbarStandard.superclass.constructor.call(this, config);
14560 this.editor = config.editor;
14561 this.editorcore = config.editor.editorcore;
14563 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
14565 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
14566 // dont call parent... till later.
14568 Roo.extend(Roo.bootstrap.HtmlEditor.ToolbarStandard, Roo.bootstrap.Navbar, {
14574 editorcore : false,
14579 "h1","h2","h3","h4","h5","h6",
14581 "abbr", "acronym", "address", "cite", "samp", "var",
14585 onRender : function(ct, position)
14587 // Roo.log("Call onRender: " + this.xtype);
14589 Roo.bootstrap.HtmlEditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
14591 this.el.dom.style.marginBottom = '0';
14593 var editorcore = this.editorcore;
14594 var editor= this.editor;
14597 var btn = function(id,cmd , toggle, handler){
14599 var event = toggle ? 'toggle' : 'click';
14604 xns: Roo.bootstrap,
14607 enableToggle:toggle !== false,
14609 pressed : toggle ? false : null,
14612 a.listeners[toggle ? 'toggle' : 'click'] = function() {
14613 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
14622 xns: Roo.bootstrap,
14623 glyphicon : 'font',
14627 xns: Roo.bootstrap,
14631 Roo.each(this.formats, function(f) {
14632 style.menu.items.push({
14634 xns: Roo.bootstrap,
14635 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
14640 editorcore.insertTag(this.tagname);
14647 children.push(style);
14650 btn('bold',false,true);
14651 btn('italic',false,true);
14652 btn('align-left', 'justifyleft',true);
14653 btn('align-center', 'justifycenter',true);
14654 btn('align-right' , 'justifyright',true);
14655 btn('link', false, false, function(btn) {
14656 //Roo.log("create link?");
14657 var url = prompt(this.createLinkText, this.defaultLinkValue);
14658 if(url && url != 'http:/'+'/'){
14659 this.editorcore.relayCmd('createlink', url);
14662 btn('list','insertunorderedlist',true);
14663 btn('pencil', false,true, function(btn){
14666 this.toggleSourceEdit(btn.pressed);
14672 xns: Roo.bootstrap,
14677 xns: Roo.bootstrap,
14682 cog.menu.items.push({
14684 xns: Roo.bootstrap,
14685 html : Clean styles,
14690 editorcore.insertTag(this.tagname);
14699 this.xtype = 'Navbar';
14701 for(var i=0;i< children.length;i++) {
14703 this.buttons.add(this.addxtypeChild(children[i]));
14707 editor.on('editorevent', this.updateToolbar, this);
14709 onBtnClick : function(id)
14711 this.editorcore.relayCmd(id);
14712 this.editorcore.focus();
14716 * Protected method that will not generally be called directly. It triggers
14717 * a toolbar update by reading the markup state of the current selection in the editor.
14719 updateToolbar: function(){
14721 if(!this.editorcore.activated){
14722 this.editor.onFirstFocus(); // is this neeed?
14726 var btns = this.buttons;
14727 var doc = this.editorcore.doc;
14728 btns.get('bold').setActive(doc.queryCommandState('bold'));
14729 btns.get('italic').setActive(doc.queryCommandState('italic'));
14730 //btns.get('underline').setActive(doc.queryCommandState('underline'));
14732 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
14733 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
14734 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
14736 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
14737 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
14740 var ans = this.editorcore.getAllAncestors();
14741 if (this.formatCombo) {
14744 var store = this.formatCombo.store;
14745 this.formatCombo.setValue("");
14746 for (var i =0; i < ans.length;i++) {
14747 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
14749 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
14757 // hides menus... - so this cant be on a menu...
14758 Roo.bootstrap.MenuMgr.hideAll();
14760 Roo.bootstrap.MenuMgr.hideAll();
14761 //this.editorsyncValue();
14763 onFirstFocus: function() {
14764 this.buttons.each(function(item){
14768 toggleSourceEdit : function(sourceEditMode){
14771 if(sourceEditMode){
14772 Roo.log("disabling buttons");
14773 this.buttons.each( function(item){
14774 if(item.cmd != 'pencil'){
14780 Roo.log("enabling buttons");
14781 if(this.editorcore.initialized){
14782 this.buttons.each( function(item){
14788 Roo.log("calling toggole on editor");
14789 // tell the editor that it's been pressed..
14790 this.editor.toggleSourceEdit(sourceEditMode);
14800 * @class Roo.bootstrap.Table.AbstractSelectionModel
14801 * @extends Roo.util.Observable
14802 * Abstract base class for grid SelectionModels. It provides the interface that should be
14803 * implemented by descendant classes. This class should not be directly instantiated.
14806 Roo.bootstrap.Table.AbstractSelectionModel = function(){
14807 this.locked = false;
14808 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
14812 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
14813 /** @ignore Called by the grid automatically. Do not call directly. */
14814 init : function(grid){
14820 * Locks the selections.
14823 this.locked = true;
14827 * Unlocks the selections.
14829 unlock : function(){
14830 this.locked = false;
14834 * Returns true if the selections are locked.
14835 * @return {Boolean}
14837 isLocked : function(){
14838 return this.locked;
14842 * @class Roo.bootstrap.Table.ColumnModel
14843 * @extends Roo.util.Observable
14844 * This is the default implementation of a ColumnModel used by the bootstrap table. It defines
14845 * the columns in the table.
14848 * @param {Object} config An Array of column config objects. See this class's
14849 * config objects for details.
14851 Roo.bootstrap.Table.ColumnModel = function(config){
14853 * The config passed into the constructor
14855 this.config = config;
14858 // if no id, create one
14859 // if the column does not have a dataIndex mapping,
14860 // map it to the order it is in the config
14861 for(var i = 0, len = config.length; i < len; i++){
14863 if(typeof c.dataIndex == "undefined"){
14866 if(typeof c.renderer == "string"){
14867 c.renderer = Roo.util.Format[c.renderer];
14869 if(typeof c.id == "undefined"){
14872 // if(c.editor && c.editor.xtype){
14873 // c.editor = Roo.factory(c.editor, Roo.grid);
14875 // if(c.editor && c.editor.isFormField){
14876 // c.editor = new Roo.grid.GridEditor(c.editor);
14879 this.lookup[c.id] = c;
14883 * The width of columns which have no width specified (defaults to 100)
14886 this.defaultWidth = 100;
14889 * Default sortable of columns which have no sortable specified (defaults to false)
14892 this.defaultSortable = false;
14896 * @event widthchange
14897 * Fires when the width of a column changes.
14898 * @param {ColumnModel} this
14899 * @param {Number} columnIndex The column index
14900 * @param {Number} newWidth The new width
14902 "widthchange": true,
14904 * @event headerchange
14905 * Fires when the text of a header changes.
14906 * @param {ColumnModel} this
14907 * @param {Number} columnIndex The column index
14908 * @param {Number} newText The new header text
14910 "headerchange": true,
14912 * @event hiddenchange
14913 * Fires when a column is hidden or "unhidden".
14914 * @param {ColumnModel} this
14915 * @param {Number} columnIndex The column index
14916 * @param {Boolean} hidden true if hidden, false otherwise
14918 "hiddenchange": true,
14920 * @event columnmoved
14921 * Fires when a column is moved.
14922 * @param {ColumnModel} this
14923 * @param {Number} oldIndex
14924 * @param {Number} newIndex
14926 "columnmoved" : true,
14928 * @event columlockchange
14929 * Fires when a column's locked state is changed
14930 * @param {ColumnModel} this
14931 * @param {Number} colIndex
14932 * @param {Boolean} locked true if locked
14934 "columnlockchange" : true
14936 Roo.bootstrap.Table.ColumnModel.superclass.constructor.call(this);
14938 Roo.extend(Roo.bootstrap.Table.ColumnModel, Roo.util.Observable, {
14940 * @cfg {String} header The header text to display in the Grid view.
14943 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
14944 * {@link Roo.data.Record} definition from which to draw the column's value. If not
14945 * specified, the column's index is used as an index into the Record's data Array.
14948 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
14949 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
14952 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
14953 * Defaults to the value of the {@link #defaultSortable} property.
14954 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
14957 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
14960 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
14963 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
14966 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
14969 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
14970 * given the cell's data value. See {@link #setRenderer}. If not specified, the
14971 * default renderer uses the raw data value.
14974 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
14978 * Returns the id of the column at the specified index.
14979 * @param {Number} index The column index
14980 * @return {String} the id
14982 getColumnId : function(index){
14983 return this.config[index].id;
14987 * Returns the column for a specified id.
14988 * @param {String} id The column id
14989 * @return {Object} the column
14991 getColumnById : function(id){
14992 return this.lookup[id];
14997 * Returns the column for a specified dataIndex.
14998 * @param {String} dataIndex The column dataIndex
14999 * @return {Object|Boolean} the column or false if not found
15001 getColumnByDataIndex: function(dataIndex){
15002 var index = this.findColumnIndex(dataIndex);
15003 return index > -1 ? this.config[index] : false;
15007 * Returns the index for a specified column id.
15008 * @param {String} id The column id
15009 * @return {Number} the index, or -1 if not found
15011 getIndexById : function(id){
15012 for(var i = 0, len = this.config.length; i < len; i++){
15013 if(this.config[i].id == id){
15021 * Returns the index for a specified column dataIndex.
15022 * @param {String} dataIndex The column dataIndex
15023 * @return {Number} the index, or -1 if not found
15026 findColumnIndex : function(dataIndex){
15027 for(var i = 0, len = this.config.length; i < len; i++){
15028 if(this.config[i].dataIndex == dataIndex){
15036 moveColumn : function(oldIndex, newIndex){
15037 var c = this.config[oldIndex];
15038 this.config.splice(oldIndex, 1);
15039 this.config.splice(newIndex, 0, c);
15040 this.dataMap = null;
15041 this.fireEvent("columnmoved", this, oldIndex, newIndex);
15044 isLocked : function(colIndex){
15045 return this.config[colIndex].locked === true;
15048 setLocked : function(colIndex, value, suppressEvent){
15049 if(this.isLocked(colIndex) == value){
15052 this.config[colIndex].locked = value;
15053 if(!suppressEvent){
15054 this.fireEvent("columnlockchange", this, colIndex, value);
15058 getTotalLockedWidth : function(){
15059 var totalWidth = 0;
15060 for(var i = 0; i < this.config.length; i++){
15061 if(this.isLocked(i) && !this.isHidden(i)){
15062 this.totalWidth += this.getColumnWidth(i);
15068 getLockedCount : function(){
15069 for(var i = 0, len = this.config.length; i < len; i++){
15070 if(!this.isLocked(i)){
15077 * Returns the number of columns.
15080 getColumnCount : function(visibleOnly){
15081 if(visibleOnly === true){
15083 for(var i = 0, len = this.config.length; i < len; i++){
15084 if(!this.isHidden(i)){
15090 return this.config.length;
15094 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
15095 * @param {Function} fn
15096 * @param {Object} scope (optional)
15097 * @return {Array} result
15099 getColumnsBy : function(fn, scope){
15101 for(var i = 0, len = this.config.length; i < len; i++){
15102 var c = this.config[i];
15103 if(fn.call(scope||this, c, i) === true){
15111 * Returns true if the specified column is sortable.
15112 * @param {Number} col The column index
15113 * @return {Boolean}
15115 isSortable : function(col){
15116 if(typeof this.config[col].sortable == "undefined"){
15117 return this.defaultSortable;
15119 return this.config[col].sortable;
15123 * Returns the rendering (formatting) function defined for the column.
15124 * @param {Number} col The column index.
15125 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
15127 getRenderer : function(col){
15128 if(!this.config[col].renderer){
15129 return Roo.bootstrap.Table.ColumnModel.defaultRenderer;
15131 return this.config[col].renderer;
15135 * Sets the rendering (formatting) function for a column.
15136 * @param {Number} col The column index
15137 * @param {Function} fn The function to use to process the cell's raw data
15138 * to return HTML markup for the grid view. The render function is called with
15139 * the following parameters:<ul>
15140 * <li>Data value.</li>
15141 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
15142 * <li>css A CSS style string to apply to the table cell.</li>
15143 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
15144 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
15145 * <li>Row index</li>
15146 * <li>Column index</li>
15147 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
15149 setRenderer : function(col, fn){
15150 this.config[col].renderer = fn;
15154 * Returns the width for the specified column.
15155 * @param {Number} col The column index
15158 getColumnWidth : function(col){
15159 return this.config[col].width * 1 || this.defaultWidth;
15163 * Sets the width for a column.
15164 * @param {Number} col The column index
15165 * @param {Number} width The new width
15167 setColumnWidth : function(col, width, suppressEvent){
15168 this.config[col].width = width;
15169 this.totalWidth = null;
15170 if(!suppressEvent){
15171 this.fireEvent("widthchange", this, col, width);
15176 * Returns the total width of all columns.
15177 * @param {Boolean} includeHidden True to include hidden column widths
15180 getTotalWidth : function(includeHidden){
15181 if(!this.totalWidth){
15182 this.totalWidth = 0;
15183 for(var i = 0, len = this.config.length; i < len; i++){
15184 if(includeHidden || !this.isHidden(i)){
15185 this.totalWidth += this.getColumnWidth(i);
15189 return this.totalWidth;
15193 * Returns the header for the specified column.
15194 * @param {Number} col The column index
15197 getColumnHeader : function(col){
15198 return this.config[col].header;
15202 * Sets the header for a column.
15203 * @param {Number} col The column index
15204 * @param {String} header The new header
15206 setColumnHeader : function(col, header){
15207 this.config[col].header = header;
15208 this.fireEvent("headerchange", this, col, header);
15212 * Returns the tooltip for the specified column.
15213 * @param {Number} col The column index
15216 getColumnTooltip : function(col){
15217 return this.config[col].tooltip;
15220 * Sets the tooltip for a column.
15221 * @param {Number} col The column index
15222 * @param {String} tooltip The new tooltip
15224 setColumnTooltip : function(col, tooltip){
15225 this.config[col].tooltip = tooltip;
15229 * Returns the dataIndex for the specified column.
15230 * @param {Number} col The column index
15233 getDataIndex : function(col){
15234 return this.config[col].dataIndex;
15238 * Sets the dataIndex for a column.
15239 * @param {Number} col The column index
15240 * @param {Number} dataIndex The new dataIndex
15242 setDataIndex : function(col, dataIndex){
15243 this.config[col].dataIndex = dataIndex;
15249 * Returns true if the cell is editable.
15250 * @param {Number} colIndex The column index
15251 * @param {Number} rowIndex The row index
15252 * @return {Boolean}
15254 isCellEditable : function(colIndex, rowIndex){
15255 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
15259 * Returns the editor defined for the cell/column.
15260 * return false or null to disable editing.
15261 * @param {Number} colIndex The column index
15262 * @param {Number} rowIndex The row index
15265 getCellEditor : function(colIndex, rowIndex){
15266 return this.config[colIndex].editor;
15270 * Sets if a column is editable.
15271 * @param {Number} col The column index
15272 * @param {Boolean} editable True if the column is editable
15274 setEditable : function(col, editable){
15275 this.config[col].editable = editable;
15280 * Returns true if the column is hidden.
15281 * @param {Number} colIndex The column index
15282 * @return {Boolean}
15284 isHidden : function(colIndex){
15285 return this.config[colIndex].hidden;
15290 * Returns true if the column width cannot be changed
15292 isFixed : function(colIndex){
15293 return this.config[colIndex].fixed;
15297 * Returns true if the column can be resized
15298 * @return {Boolean}
15300 isResizable : function(colIndex){
15301 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
15304 * Sets if a column is hidden.
15305 * @param {Number} colIndex The column index
15306 * @param {Boolean} hidden True if the column is hidden
15308 setHidden : function(colIndex, hidden){
15309 this.config[colIndex].hidden = hidden;
15310 this.totalWidth = null;
15311 this.fireEvent("hiddenchange", this, colIndex, hidden);
15315 * Sets the editor for a column.
15316 * @param {Number} col The column index
15317 * @param {Object} editor The editor object
15319 setEditor : function(col, editor){
15320 this.config[col].editor = editor;
15324 Roo.bootstrap.Table.ColumnModel.defaultRenderer = function(value){
15325 if(typeof value == "string" && value.length < 1){
15331 // Alias for backwards compatibility
15332 Roo.bootstrap.Table.DefaultColumnModel = Roo.bootstrap.Table.ColumnModel;
15335 * @extends Roo.bootstrap.Table.AbstractSelectionModel
15336 * @class Roo.bootstrap.Table.RowSelectionModel
15337 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
15338 * It supports multiple selections and keyboard selection/navigation.
15340 * @param {Object} config
15343 Roo.bootstrap.Table.RowSelectionModel = function(config){
15344 Roo.apply(this, config);
15345 this.selections = new Roo.util.MixedCollection(false, function(o){
15350 this.lastActive = false;
15354 * @event selectionchange
15355 * Fires when the selection changes
15356 * @param {SelectionModel} this
15358 "selectionchange" : true,
15360 * @event afterselectionchange
15361 * Fires after the selection changes (eg. by key press or clicking)
15362 * @param {SelectionModel} this
15364 "afterselectionchange" : true,
15366 * @event beforerowselect
15367 * Fires when a row is selected being selected, return false to cancel.
15368 * @param {SelectionModel} this
15369 * @param {Number} rowIndex The selected index
15370 * @param {Boolean} keepExisting False if other selections will be cleared
15372 "beforerowselect" : true,
15375 * Fires when a row is selected.
15376 * @param {SelectionModel} this
15377 * @param {Number} rowIndex The selected index
15378 * @param {Roo.data.Record} r The record
15380 "rowselect" : true,
15382 * @event rowdeselect
15383 * Fires when a row is deselected.
15384 * @param {SelectionModel} this
15385 * @param {Number} rowIndex The selected index
15387 "rowdeselect" : true
15389 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
15390 this.locked = false;
15393 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
15395 * @cfg {Boolean} singleSelect
15396 * True to allow selection of only one row at a time (defaults to false)
15398 singleSelect : false,
15401 initEvents : function(){
15403 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
15404 this.grid.on("mousedown", this.handleMouseDown, this);
15405 }else{ // allow click to work like normal
15406 this.grid.on("rowclick", this.handleDragableRowClick, this);
15409 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
15410 "up" : function(e){
15412 this.selectPrevious(e.shiftKey);
15413 }else if(this.last !== false && this.lastActive !== false){
15414 var last = this.last;
15415 this.selectRange(this.last, this.lastActive-1);
15416 this.grid.getView().focusRow(this.lastActive);
15417 if(last !== false){
15421 this.selectFirstRow();
15423 this.fireEvent("afterselectionchange", this);
15425 "down" : function(e){
15427 this.selectNext(e.shiftKey);
15428 }else if(this.last !== false && this.lastActive !== false){
15429 var last = this.last;
15430 this.selectRange(this.last, this.lastActive+1);
15431 this.grid.getView().focusRow(this.lastActive);
15432 if(last !== false){
15436 this.selectFirstRow();
15438 this.fireEvent("afterselectionchange", this);
15443 var view = this.grid.view;
15444 view.on("refresh", this.onRefresh, this);
15445 view.on("rowupdated", this.onRowUpdated, this);
15446 view.on("rowremoved", this.onRemove, this);
15450 onRefresh : function(){
15451 var ds = this.grid.dataSource, i, v = this.grid.view;
15452 var s = this.selections;
15453 s.each(function(r){
15454 if((i = ds.indexOfId(r.id)) != -1){
15463 onRemove : function(v, index, r){
15464 this.selections.remove(r);
15468 onRowUpdated : function(v, index, r){
15469 if(this.isSelected(r)){
15470 v.onRowSelect(index);
15476 * @param {Array} records The records to select
15477 * @param {Boolean} keepExisting (optional) True to keep existing selections
15479 selectRecords : function(records, keepExisting){
15481 this.clearSelections();
15483 var ds = this.grid.dataSource;
15484 for(var i = 0, len = records.length; i < len; i++){
15485 this.selectRow(ds.indexOf(records[i]), true);
15490 * Gets the number of selected rows.
15493 getCount : function(){
15494 return this.selections.length;
15498 * Selects the first row in the grid.
15500 selectFirstRow : function(){
15505 * Select the last row.
15506 * @param {Boolean} keepExisting (optional) True to keep existing selections
15508 selectLastRow : function(keepExisting){
15509 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
15513 * Selects the row immediately following the last selected row.
15514 * @param {Boolean} keepExisting (optional) True to keep existing selections
15516 selectNext : function(keepExisting){
15517 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
15518 this.selectRow(this.last+1, keepExisting);
15519 this.grid.getView().focusRow(this.last);
15524 * Selects the row that precedes the last selected row.
15525 * @param {Boolean} keepExisting (optional) True to keep existing selections
15527 selectPrevious : function(keepExisting){
15529 this.selectRow(this.last-1, keepExisting);
15530 this.grid.getView().focusRow(this.last);
15535 * Returns the selected records
15536 * @return {Array} Array of selected records
15538 getSelections : function(){
15539 return [].concat(this.selections.items);
15543 * Returns the first selected record.
15546 getSelected : function(){
15547 return this.selections.itemAt(0);
15552 * Clears all selections.
15554 clearSelections : function(fast){
15555 if(this.locked) return;
15557 var ds = this.grid.dataSource;
15558 var s = this.selections;
15559 s.each(function(r){
15560 this.deselectRow(ds.indexOfId(r.id));
15564 this.selections.clear();
15571 * Selects all rows.
15573 selectAll : function(){
15574 if(this.locked) return;
15575 this.selections.clear();
15576 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
15577 this.selectRow(i, true);
15582 * Returns True if there is a selection.
15583 * @return {Boolean}
15585 hasSelection : function(){
15586 return this.selections.length > 0;
15590 * Returns True if the specified row is selected.
15591 * @param {Number/Record} record The record or index of the record to check
15592 * @return {Boolean}
15594 isSelected : function(index){
15595 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
15596 return (r && this.selections.key(r.id) ? true : false);
15600 * Returns True if the specified record id is selected.
15601 * @param {String} id The id of record to check
15602 * @return {Boolean}
15604 isIdSelected : function(id){
15605 return (this.selections.key(id) ? true : false);
15609 handleMouseDown : function(e, t){
15610 var view = this.grid.getView(), rowIndex;
15611 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
15614 if(e.shiftKey && this.last !== false){
15615 var last = this.last;
15616 this.selectRange(last, rowIndex, e.ctrlKey);
15617 this.last = last; // reset the last
15618 view.focusRow(rowIndex);
15620 var isSelected = this.isSelected(rowIndex);
15621 if(e.button !== 0 && isSelected){
15622 view.focusRow(rowIndex);
15623 }else if(e.ctrlKey && isSelected){
15624 this.deselectRow(rowIndex);
15625 }else if(!isSelected){
15626 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
15627 view.focusRow(rowIndex);
15630 this.fireEvent("afterselectionchange", this);
15633 handleDragableRowClick : function(grid, rowIndex, e)
15635 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
15636 this.selectRow(rowIndex, false);
15637 grid.view.focusRow(rowIndex);
15638 this.fireEvent("afterselectionchange", this);
15643 * Selects multiple rows.
15644 * @param {Array} rows Array of the indexes of the row to select
15645 * @param {Boolean} keepExisting (optional) True to keep existing selections
15647 selectRows : function(rows, keepExisting){
15649 this.clearSelections();
15651 for(var i = 0, len = rows.length; i < len; i++){
15652 this.selectRow(rows[i], true);
15657 * Selects a range of rows. All rows in between startRow and endRow are also selected.
15658 * @param {Number} startRow The index of the first row in the range
15659 * @param {Number} endRow The index of the last row in the range
15660 * @param {Boolean} keepExisting (optional) True to retain existing selections
15662 selectRange : function(startRow, endRow, keepExisting){
15663 if(this.locked) return;
15665 this.clearSelections();
15667 if(startRow <= endRow){
15668 for(var i = startRow; i <= endRow; i++){
15669 this.selectRow(i, true);
15672 for(var i = startRow; i >= endRow; i--){
15673 this.selectRow(i, true);
15679 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
15680 * @param {Number} startRow The index of the first row in the range
15681 * @param {Number} endRow The index of the last row in the range
15683 deselectRange : function(startRow, endRow, preventViewNotify){
15684 if(this.locked) return;
15685 for(var i = startRow; i <= endRow; i++){
15686 this.deselectRow(i, preventViewNotify);
15692 * @param {Number} row The index of the row to select
15693 * @param {Boolean} keepExisting (optional) True to keep existing selections
15695 selectRow : function(index, keepExisting, preventViewNotify){
15696 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
15697 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
15698 if(!keepExisting || this.singleSelect){
15699 this.clearSelections();
15701 var r = this.grid.dataSource.getAt(index);
15702 this.selections.add(r);
15703 this.last = this.lastActive = index;
15704 if(!preventViewNotify){
15705 this.grid.getView().onRowSelect(index);
15707 this.fireEvent("rowselect", this, index, r);
15708 this.fireEvent("selectionchange", this);
15714 * @param {Number} row The index of the row to deselect
15716 deselectRow : function(index, preventViewNotify){
15717 if(this.locked) return;
15718 if(this.last == index){
15721 if(this.lastActive == index){
15722 this.lastActive = false;
15724 var r = this.grid.dataSource.getAt(index);
15725 this.selections.remove(r);
15726 if(!preventViewNotify){
15727 this.grid.getView().onRowDeselect(index);
15729 this.fireEvent("rowdeselect", this, index);
15730 this.fireEvent("selectionchange", this);
15734 restoreLast : function(){
15736 this.last = this._last;
15741 acceptsNav : function(row, col, cm){
15742 return !cm.isHidden(col) && cm.isCellEditable(col, row);
15746 onEditorKey : function(field, e){
15747 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
15752 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
15754 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
15756 }else if(k == e.ENTER && !e.ctrlKey){
15760 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
15762 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
15764 }else if(k == e.ESC){
15768 g.startEditing(newCell[0], newCell[1]);
15779 * @class Roo.bootstrap.MessageBar
15780 * @extends Roo.bootstrap.Component
15781 * Bootstrap MessageBar class
15782 * @cfg {String} html contents of the MessageBar
15783 * @cfg {String} weight (info | success | warning | danger) default info
15784 * @cfg {String} beforeClass insert the bar before the given class
15785 * @cfg {Boolean} closable (true | false) default false
15786 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
15789 * Create a new Element
15790 * @param {Object} config The config object
15793 Roo.bootstrap.MessageBar = function(config){
15794 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
15797 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
15803 beforeClass: 'bootstrap-sticky-wrap',
15805 getAutoCreate : function(){
15809 cls: 'alert alert-dismissable alert-' + this.weight,
15814 html: this.html || ''
15820 cfg.cls += ' alert-messages-fixed';
15834 onRender : function(ct, position)
15836 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
15839 var cfg = Roo.apply({}, this.getAutoCreate());
15843 cfg.cls += ' ' + this.cls;
15846 cfg.style = this.style;
15848 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
15850 this.el.setVisibilityMode(Roo.Element.DISPLAY);
15853 this.el.select('>button.close').on('click', this.hide, this);
15859 if (!this.rendered) {
15865 this.fireEvent('show', this);
15871 if (!this.rendered) {
15877 this.fireEvent('hide', this);
15880 update : function()
15882 // var e = this.el.dom.firstChild;
15884 // if(this.closable){
15885 // e = e.nextSibling;
15888 // e.data = this.html || '';
15890 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';