4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
21 * Do not use directly - it does not do anything..
22 * @param {Object} config The config object
27 Roo.bootstrap.Component = function(config){
28 Roo.bootstrap.Component.superclass.constructor.call(this, config);
31 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
34 allowDomMove : false, // to stop relocations in parent onRender...
42 initEvents : function() { },
48 can_build_overlaid : true,
55 // returns the parent component..
56 return Roo.ComponentMgr.get(this.parentId)
62 onRender : function(ct, position)
64 // Roo.log("Call onRender: " + this.xtype);
66 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
69 if (this.el.attr('xtype')) {
70 this.el.attr('xtypex', this.el.attr('xtype'));
71 this.el.dom.removeAttribute('xtype');
81 var cfg = Roo.apply({}, this.getAutoCreate());
84 // fill in the extra attributes
85 if (this.xattr && typeof(this.xattr) =='object') {
86 for (var i in this.xattr) {
87 cfg[i] = this.xattr[i];
92 cfg.dataId = this.dataId;
96 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
99 if (this.style) { // fixme needs to support more complex style data.
100 cfg.style = this.style;
104 cfg.name = this.name;
107 this.el = ct.createChild(cfg, position);
109 if(this.tabIndex !== undefined){
110 this.el.dom.setAttribute('tabIndex', this.tabIndex);
117 getChildContainer : function()
123 addxtype : function(tree,cntr)
127 cn = Roo.factory(tree);
129 cn.parentType = this.xtype; //??
130 cn.parentId = this.id;
132 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
134 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
136 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
138 var build_from_html = Roo.XComponent.build_from_html;
140 var is_body = (tree.xtype == 'Body') ;
142 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
144 var self_cntr_el = Roo.get(this[cntr]());
146 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
147 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
148 return this.addxtypeChild(tree,cntr);
151 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
154 return this.addxtypeChild(Roo.apply({}, tree),cntr);
157 Roo.log('skipping render');
165 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
171 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
175 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
180 addxtypeChild : function (tree, cntr)
182 Roo.log('addxtypeChild:' + cntr);
184 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
187 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
188 (typeof(tree['flexy:foreach']) != 'undefined');
193 // render the element if it's not BODY.
194 if (tree.xtype != 'Body') {
196 cn = Roo.factory(tree);
198 cn.parentType = this.xtype; //??
199 cn.parentId = this.id;
201 var build_from_html = Roo.XComponent.build_from_html;
204 // does the container contain child eleemnts with 'xtype' attributes.
205 // that match this xtype..
206 // note - when we render we create these as well..
207 // so we should check to see if body has xtype set.
208 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
210 var self_cntr_el = Roo.get(this[cntr]());
211 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
213 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
214 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
220 //echild.dom.removeAttribute('xtype');
222 Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
229 // if object has flexy:if - then it may or may not be rendered.
230 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
231 // skip a flexy if element.
232 Roo.log('skipping render');
235 // actually if flexy:foreach is found, we really want to create
236 // multiple copies here...
238 //Roo.log(this[cntr]());
239 cn.render(this[cntr]());
241 // then add the element..
248 if (typeof (tree.menu) != 'undefined') {
249 tree.menu.parentType = cn.xtype;
250 tree.menu.triggerEl = cn.el;
251 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
255 if (!tree.items || !tree.items.length) {
259 var items = tree.items;
262 //Roo.log(items.length);
264 for(var i =0;i < items.length;i++) {
265 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
286 * @class Roo.bootstrap.Body
287 * @extends Roo.bootstrap.Component
288 * Bootstrap Body class
292 * @param {Object} config The config object
295 Roo.bootstrap.Body = function(config){
296 Roo.bootstrap.Body.superclass.constructor.call(this, config);
297 this.el = Roo.get(document.body);
300 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
305 onRender : function(ct, position){
308 //this.el.addClass([this.fieldClass, this.cls]);
326 * @class Roo.bootstrap.ButtonGroup
327 * @extends Roo.bootstrap.Component
328 * Bootstrap ButtonGroup class
329 * @cfg {String} size lg | sm | xs (default empty normal)
330 * @cfg {String} align vertical | justified (default none)
331 * @cfg {String} direction up | down (default down)
332 * @cfg {Boolean} toolbar false | true
333 * @cfg {Boolean} btn true | false
338 * @param {Object} config The config object
341 Roo.bootstrap.ButtonGroup = function(config){
342 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
345 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
353 getAutoCreate : function(){
359 cfg.html = this.html || cfg.html;
370 if (['vertical','justified'].indexOf(this.align)!==-1) {
371 cfg.cls = 'btn-group-' + this.align;
373 if (this.align == 'justified') {
374 console.log(this.items);
378 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
379 cfg.cls += ' btn-group-' + this.size;
382 if (this.direction == 'up') {
383 cfg.cls += ' dropup' ;
399 * @class Roo.bootstrap.Button
400 * @extends Roo.bootstrap.Component
401 * Bootstrap Button class
402 * @cfg {String} html The button content
403 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger | link
404 * @cfg {String} size empty | lg | sm | xs
405 * @cfg {String} tag empty | a | input | submit
406 * @cfg {String} href empty or href
407 * @cfg {Boolean} disabled false | true
408 * @cfg {Boolean} isClose false | true
409 * @cfg {String} glyphicon empty | adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out
410 * @cfg {String} badge text for badge
411 * @cfg {String} theme default (or empty) | glow
412 * @cfg {Boolean} inverse false | true
413 * @cfg {Boolean} toggle false | true
414 * @cfg {String} ontext text for on toggle state
415 * @cfg {String} offtext text for off toggle state
416 * @cfg {Boolean} defaulton true | false
417 * @cfg {Boolean} preventDefault (true | false) default true
418 * @cfg {Boolean} removeClass true | false remove the standard class..
419 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
422 * Create a new button
423 * @param {Object} config The config object
427 Roo.bootstrap.Button = function(config){
428 Roo.bootstrap.Button.superclass.constructor.call(this, config);
433 * When a butotn is pressed
434 * @param {Roo.EventObject} e
439 * After the button has been toggles
440 * @param {Roo.EventObject} e
441 * @param {boolean} pressed (also available as button.pressed)
447 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
465 preventDefault: true,
474 getAutoCreate : function(){
482 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
483 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
488 cfg.html = this.html || cfg.html;
490 if (this.toggle == true) {
493 cls: 'slider-frame roo-button',
498 'data-off-text':'OFF',
499 cls: 'slider-button',
505 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
506 cfg.cls += ' '+this.weight;
515 cfg["aria-hidden"] = true;
517 cfg.html = "×";
523 if (this.theme==='default') {
524 cfg.cls = 'btn roo-button';
526 //if (this.parentType != 'Navbar') {
527 this.weight = this.weight.length ? this.weight : 'default';
529 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
531 cfg.cls += ' btn-' + this.weight;
533 } else if (this.theme==='glow') {
536 cfg.cls = 'btn-glow roo-button';
538 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
540 cfg.cls += ' ' + this.weight;
546 this.cls += ' inverse';
551 cfg.cls += ' active';
555 cfg.disabled = 'disabled';
559 Roo.log('changing to ul' );
561 this.glyphicon = 'caret';
564 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
566 //gsRoo.log(this.parentType);
567 if (this.parentType === 'Navbar' && !this.parent().bar) {
568 Roo.log('changing to li?');
577 href : this.href || '#'
580 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
581 cfg.cls += ' dropdown';
588 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
590 if (this.glyphicon) {
591 cfg.html = ' ' + cfg.html;
596 cls: 'glyphicon glyphicon-' + this.glyphicon
606 // cfg.cls='btn roo-button';
610 var value = cfg.html;
615 cls: 'glyphicon glyphicon-' + this.glyphicon,
634 cfg.cls += ' dropdown';
635 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
638 if (cfg.tag !== 'a' && this.href !== '') {
639 throw "Tag must be a to set href.";
640 } else if (this.href.length > 0) {
641 cfg.href = this.href;
644 if(this.removeClass){
649 cfg.target = this.target;
654 initEvents: function() {
655 // Roo.log('init events?');
656 // Roo.log(this.el.dom);
657 if (this.el.hasClass('roo-button')) {
658 this.el.on('click', this.onClick, this);
660 this.el.select('.roo-button').on('click', this.onClick, this);
666 onClick : function(e)
672 Roo.log('button on click ');
673 if(this.preventDefault){
676 if (this.pressed === true || this.pressed === false) {
677 this.pressed = !this.pressed;
678 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
679 this.fireEvent('toggle', this, e, this.pressed);
683 this.fireEvent('click', this, e);
687 * Enables this button
691 this.disabled = false;
692 this.el.removeClass('disabled');
696 * Disable this button
700 this.disabled = true;
701 this.el.addClass('disabled');
704 * sets the active state on/off,
705 * @param {Boolean} state (optional) Force a particular state
707 setActive : function(v) {
709 this.el[v ? 'addClass' : 'removeClass']('active');
712 * toggles the current active state
714 toggleActive : function()
716 var active = this.el.hasClass('active');
717 this.setActive(!active);
734 * @class Roo.bootstrap.Column
735 * @extends Roo.bootstrap.Component
736 * Bootstrap Column class
737 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
738 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
739 * @cfg {Number} md colspan out of 12 for computer-sized screens
740 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
741 * @cfg {String} html content of column.
744 * Create a new Column
745 * @param {Object} config The config object
748 Roo.bootstrap.Column = function(config){
749 Roo.bootstrap.Column.superclass.constructor.call(this, config);
752 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
761 getAutoCreate : function(){
762 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
770 ['xs','sm','md','lg'].map(function(size){
771 if (settings[size]) {
772 cfg.cls += ' col-' + size + '-' + settings[size];
775 if (this.html.length) {
776 cfg.html = this.html;
795 * @class Roo.bootstrap.Container
796 * @extends Roo.bootstrap.Component
797 * Bootstrap Container class
798 * @cfg {Boolean} jumbotron is it a jumbotron element
799 * @cfg {String} html content of element
800 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
801 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
802 * @cfg {String} header content of header (for panel)
803 * @cfg {String} footer content of footer (for panel)
804 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
807 * Create a new Container
808 * @param {Object} config The config object
811 Roo.bootstrap.Container = function(config){
812 Roo.bootstrap.Container.superclass.constructor.call(this, config);
815 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
825 getChildContainer : function() {
831 if (this.panel.length) {
832 return this.el.select('.panel-body',true).first();
839 getAutoCreate : function(){
845 if (this.jumbotron) {
846 cfg.cls = 'jumbotron';
849 cfg.cls = this.cls + '';
852 if (this.sticky.length) {
854 var bd = Roo.get(document.body);
855 if (!bd.hasClass('bootstrap-sticky')) {
856 bd.addClass('bootstrap-sticky');
857 Roo.select('html',true).setStyle('height', '100%');
860 cfg.cls += 'bootstrap-sticky-' + this.sticky;
864 if (this.well.length) {
868 cfg.cls +=' well well-' +this.well;
878 if (this.panel.length) {
879 cfg.cls += ' panel panel-' + this.panel;
881 if (this.header.length) {
884 cls : 'panel-heading',
900 if (this.footer.length) {
902 cls : 'panel-footer',
910 body.html = this.html || cfg.html;
912 if (!cfg.cls.length) {
913 cfg.cls = 'container';
930 * @class Roo.bootstrap.Img
931 * @extends Roo.bootstrap.Component
932 * Bootstrap Img class
933 * @cfg {Boolean} imgResponsive false | true
934 * @cfg {String} border rounded | circle | thumbnail
935 * @cfg {String} src image source
936 * @cfg {String} alt image alternative text
937 * @cfg {String} href a tag href
938 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
942 * @param {Object} config The config object
945 Roo.bootstrap.Img = function(config){
946 Roo.bootstrap.Img.superclass.constructor.call(this, config);
952 * The img click event for the img.
953 * @param {Roo.EventObject} e
959 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
967 getAutoCreate : function(){
971 cls: 'img-responsive',
975 cfg.html = this.html || cfg.html;
977 cfg.src = this.src || cfg.src;
979 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
980 cfg.cls += ' img-' + this.border;
997 a.target = this.target;
1003 return (this.href) ? a : cfg;
1006 initEvents: function() {
1009 this.el.on('click', this.onClick, this);
1013 onClick : function(e)
1015 Roo.log('img onclick');
1016 this.fireEvent('click', this, e);
1029 * @class Roo.bootstrap.Header
1030 * @extends Roo.bootstrap.Component
1031 * Bootstrap Header class
1032 * @cfg {String} html content of header
1033 * @cfg {Number} level (1|2|3|4|5|6) default 1
1036 * Create a new Header
1037 * @param {Object} config The config object
1041 Roo.bootstrap.Header = function(config){
1042 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1045 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1053 getAutoCreate : function(){
1056 tag: 'h' + (1 *this.level),
1057 html: this.html || 'fill in html'
1069 * Ext JS Library 1.1.1
1070 * Copyright(c) 2006-2007, Ext JS, LLC.
1072 * Originally Released Under LGPL - original licence link has changed is not relivant.
1075 * <script type="text/javascript">
1079 * @class Roo.bootstrap.MenuMgr
1080 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1083 Roo.bootstrap.MenuMgr = function(){
1084 var menus, active, groups = {}, attached = false, lastShow = new Date();
1086 // private - called when first menu is created
1089 active = new Roo.util.MixedCollection();
1090 Roo.get(document).addKeyListener(27, function(){
1091 if(active.length > 0){
1099 if(active && active.length > 0){
1100 var c = active.clone();
1110 if(active.length < 1){
1111 Roo.get(document).un("mouseup", onMouseDown);
1119 var last = active.last();
1120 lastShow = new Date();
1123 Roo.get(document).on("mouseup", onMouseDown);
1128 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1129 m.parentMenu.activeChild = m;
1130 }else if(last && last.isVisible()){
1131 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1136 function onBeforeHide(m){
1138 m.activeChild.hide();
1140 if(m.autoHideTimer){
1141 clearTimeout(m.autoHideTimer);
1142 delete m.autoHideTimer;
1147 function onBeforeShow(m){
1148 var pm = m.parentMenu;
1149 if(!pm && !m.allowOtherMenus){
1151 }else if(pm && pm.activeChild && active != m){
1152 pm.activeChild.hide();
1157 function onMouseDown(e){
1158 Roo.log("on MouseDown");
1159 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1167 function onBeforeCheck(mi, state){
1169 var g = groups[mi.group];
1170 for(var i = 0, l = g.length; i < l; i++){
1172 g[i].setChecked(false);
1181 * Hides all menus that are currently visible
1183 hideAll : function(){
1188 register : function(menu){
1192 menus[menu.id] = menu;
1193 menu.on("beforehide", onBeforeHide);
1194 menu.on("hide", onHide);
1195 menu.on("beforeshow", onBeforeShow);
1196 menu.on("show", onShow);
1198 if(g && menu.events["checkchange"]){
1202 groups[g].push(menu);
1203 menu.on("checkchange", onCheck);
1208 * Returns a {@link Roo.menu.Menu} object
1209 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1210 * be used to generate and return a new Menu instance.
1212 get : function(menu){
1213 if(typeof menu == "string"){ // menu id
1215 }else if(menu.events){ // menu instance
1218 /*else if(typeof menu.length == 'number'){ // array of menu items?
1219 return new Roo.bootstrap.Menu({items:menu});
1220 }else{ // otherwise, must be a config
1221 return new Roo.bootstrap.Menu(menu);
1228 unregister : function(menu){
1229 delete menus[menu.id];
1230 menu.un("beforehide", onBeforeHide);
1231 menu.un("hide", onHide);
1232 menu.un("beforeshow", onBeforeShow);
1233 menu.un("show", onShow);
1235 if(g && menu.events["checkchange"]){
1236 groups[g].remove(menu);
1237 menu.un("checkchange", onCheck);
1242 registerCheckable : function(menuItem){
1243 var g = menuItem.group;
1248 groups[g].push(menuItem);
1249 menuItem.on("beforecheckchange", onBeforeCheck);
1254 unregisterCheckable : function(menuItem){
1255 var g = menuItem.group;
1257 groups[g].remove(menuItem);
1258 menuItem.un("beforecheckchange", onBeforeCheck);
1270 * @class Roo.bootstrap.Menu
1271 * @extends Roo.bootstrap.Component
1272 * Bootstrap Menu class - container for MenuItems
1273 * @cfg {String} type type of menu
1277 * @param {Object} config The config object
1281 Roo.bootstrap.Menu = function(config){
1282 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1283 if (this.registerMenu) {
1284 Roo.bootstrap.MenuMgr.register(this);
1289 * Fires before this menu is displayed
1290 * @param {Roo.menu.Menu} this
1295 * Fires before this menu is hidden
1296 * @param {Roo.menu.Menu} this
1301 * Fires after this menu is displayed
1302 * @param {Roo.menu.Menu} this
1307 * Fires after this menu is hidden
1308 * @param {Roo.menu.Menu} this
1313 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1314 * @param {Roo.menu.Menu} this
1315 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1316 * @param {Roo.EventObject} e
1321 * Fires when the mouse is hovering over this menu
1322 * @param {Roo.menu.Menu} this
1323 * @param {Roo.EventObject} e
1324 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1329 * Fires when the mouse exits this menu
1330 * @param {Roo.menu.Menu} this
1331 * @param {Roo.EventObject} e
1332 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1337 * Fires when a menu item contained in this menu is clicked
1338 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1339 * @param {Roo.EventObject} e
1343 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1346 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1350 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1353 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1355 registerMenu : true,
1357 menuItems :false, // stores the menu items..
1363 getChildContainer : function() {
1367 getAutoCreate : function(){
1369 //if (['right'].indexOf(this.align)!==-1) {
1370 // cfg.cn[1].cls += ' pull-right'
1374 cls : 'dropdown-menu' ,
1375 style : 'z-index:1000'
1379 if (this.type === 'submenu') {
1380 cfg.cls = 'submenu active'
1385 initEvents : function() {
1387 // Roo.log("ADD event");
1388 // Roo.log(this.triggerEl.dom);
1389 this.triggerEl.on('click', this.onTriggerPress, this);
1390 this.triggerEl.addClass('dropdown-toggle');
1391 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1393 this.el.on("mouseover", this.onMouseOver, this);
1394 this.el.on("mouseout", this.onMouseOut, this);
1398 findTargetItem : function(e){
1399 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1403 //Roo.log(t); Roo.log(t.id);
1405 //Roo.log(this.menuitems);
1406 return this.menuitems.get(t.id);
1408 //return this.items.get(t.menuItemId);
1413 onClick : function(e){
1414 Roo.log("menu.onClick");
1415 var t = this.findTargetItem(e);
1421 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1422 if(t == this.activeItem && t.shouldDeactivate(e)){
1423 this.activeItem.deactivate();
1424 delete this.activeItem;
1428 this.setActiveItem(t, true);
1435 Roo.log('pass click event');
1439 this.fireEvent("click", this, t, e);
1443 onMouseOver : function(e){
1444 var t = this.findTargetItem(e);
1447 // if(t.canActivate && !t.disabled){
1448 // this.setActiveItem(t, true);
1452 this.fireEvent("mouseover", this, e, t);
1454 isVisible : function(){
1455 return !this.hidden;
1457 onMouseOut : function(e){
1458 var t = this.findTargetItem(e);
1461 // if(t == this.activeItem && t.shouldDeactivate(e)){
1462 // this.activeItem.deactivate();
1463 // delete this.activeItem;
1466 this.fireEvent("mouseout", this, e, t);
1471 * Displays this menu relative to another element
1472 * @param {String/HTMLElement/Roo.Element} element The element to align to
1473 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1474 * the element (defaults to this.defaultAlign)
1475 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1477 show : function(el, pos, parentMenu){
1478 this.parentMenu = parentMenu;
1482 this.fireEvent("beforeshow", this);
1483 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1486 * Displays this menu at a specific xy position
1487 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1488 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1490 showAt : function(xy, parentMenu, /* private: */_e){
1491 this.parentMenu = parentMenu;
1496 this.fireEvent("beforeshow", this);
1498 //xy = this.el.adjustForConstraints(xy);
1500 //this.el.setXY(xy);
1502 this.hideMenuItems();
1503 this.hidden = false;
1504 this.triggerEl.addClass('open');
1506 this.fireEvent("show", this);
1512 this.doFocus.defer(50, this);
1516 doFocus : function(){
1518 this.focusEl.focus();
1523 * Hides this menu and optionally all parent menus
1524 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1526 hide : function(deep){
1528 this.hideMenuItems();
1529 if(this.el && this.isVisible()){
1530 this.fireEvent("beforehide", this);
1531 if(this.activeItem){
1532 this.activeItem.deactivate();
1533 this.activeItem = null;
1535 this.triggerEl.removeClass('open');;
1537 this.fireEvent("hide", this);
1539 if(deep === true && this.parentMenu){
1540 this.parentMenu.hide(true);
1544 onTriggerPress : function(e)
1547 Roo.log('trigger press');
1548 //Roo.log(e.getTarget());
1549 // Roo.log(this.triggerEl.dom);
1550 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1553 if (this.isVisible()) {
1557 this.show(this.triggerEl, false, false);
1566 hideMenuItems : function()
1568 //$(backdrop).remove()
1569 Roo.select('.open',true).each(function(aa) {
1571 aa.removeClass('open');
1572 //var parent = getParent($(this))
1573 //var relatedTarget = { relatedTarget: this }
1575 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1576 //if (e.isDefaultPrevented()) return
1577 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1580 addxtypeChild : function (tree, cntr) {
1581 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1583 this.menuitems.add(comp);
1604 * @class Roo.bootstrap.MenuItem
1605 * @extends Roo.bootstrap.Component
1606 * Bootstrap MenuItem class
1607 * @cfg {String} html the menu label
1608 * @cfg {String} href the link
1609 * @cfg {Boolean} preventDefault (true | false) default true
1613 * Create a new MenuItem
1614 * @param {Object} config The config object
1618 Roo.bootstrap.MenuItem = function(config){
1619 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1624 * The raw click event for the entire grid.
1625 * @param {Roo.EventObject} e
1631 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1635 preventDefault: true,
1637 getAutoCreate : function(){
1640 cls: 'dropdown-menu-item',
1650 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1651 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1655 initEvents: function() {
1657 //this.el.select('a').on('click', this.onClick, this);
1660 onClick : function(e)
1662 Roo.log('item on click ');
1663 //if(this.preventDefault){
1664 // e.preventDefault();
1666 //this.parent().hideMenuItems();
1668 this.fireEvent('click', this, e);
1687 * @class Roo.bootstrap.MenuSeparator
1688 * @extends Roo.bootstrap.Component
1689 * Bootstrap MenuSeparator class
1692 * Create a new MenuItem
1693 * @param {Object} config The config object
1697 Roo.bootstrap.MenuSeparator = function(config){
1698 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1701 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1703 getAutoCreate : function(){
1718 <div class="modal fade">
1719 <div class="modal-dialog">
1720 <div class="modal-content">
1721 <div class="modal-header">
1722 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1723 <h4 class="modal-title">Modal title</h4>
1725 <div class="modal-body">
1726 <p>One fine body…</p>
1728 <div class="modal-footer">
1729 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1730 <button type="button" class="btn btn-primary">Save changes</button>
1732 </div><!-- /.modal-content -->
1733 </div><!-- /.modal-dialog -->
1734 </div><!-- /.modal -->
1744 * @class Roo.bootstrap.Modal
1745 * @extends Roo.bootstrap.Component
1746 * Bootstrap Modal class
1747 * @cfg {String} title Title of dialog
1748 * @cfg {Array} buttons Array of buttons or standard button set..
1751 * Create a new Modal Dialog
1752 * @param {Object} config The config object
1755 Roo.bootstrap.Modal = function(config){
1756 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1761 * The raw btnclick event for the button
1762 * @param {Roo.EventObject} e
1768 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1770 title : 'test dialog',
1774 onRender : function(ct, position)
1776 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1779 var cfg = Roo.apply({}, this.getAutoCreate());
1782 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1784 //if (!cfg.name.length) {
1788 cfg.cls += ' ' + this.cls;
1791 cfg.style = this.style;
1793 this.el = Roo.get(document.body).createChild(cfg, position);
1795 //var type = this.el.dom.type;
1797 if(this.tabIndex !== undefined){
1798 this.el.dom.setAttribute('tabIndex', this.tabIndex);
1803 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1804 this.maskEl.enableDisplayMode("block");
1806 //this.el.addClass("x-dlg-modal");
1809 Roo.each(this.buttons, function(bb) {
1810 b = Roo.apply({}, bb);
1811 b.xns = b.xns || Roo.bootstrap;
1812 b.xtype = b.xtype || 'Button';
1813 if (typeof(b.listeners) == 'undefined') {
1814 b.listeners = { click : this.onButtonClick.createDelegate(this) };
1817 var btn = Roo.factory(b);
1819 btn.onRender(this.el.select('.modal-footer').first());
1823 // render the children.
1826 if(typeof(this.items) != 'undefined'){
1827 var items = this.items;
1830 for(var i =0;i < items.length;i++) {
1831 nitems.push(this.addxtype(Roo.apply({}, items[i])));
1835 this.items = nitems;
1837 //this.el.addClass([this.fieldClass, this.cls]);
1840 getAutoCreate : function(){
1845 html : this.html || ''
1853 cls: "modal-dialog",
1856 cls : "modal-content",
1859 cls : 'modal-header',
1868 cls : 'modal-title',
1876 cls : 'modal-footer'
1892 getChildContainer : function() {
1894 return this.el.select('.modal-body',true).first();
1897 getButtonContainer : function() {
1898 return this.el.select('.modal-footer',true).first();
1901 initEvents : function()
1903 this.el.select('.modal-header .close').on('click', this.hide, this);
1905 // this.addxtype(this);
1909 if (!this.rendered) {
1913 this.el.addClass('on');
1914 this.el.removeClass('fade');
1915 this.el.setStyle('display', 'block');
1916 Roo.get(document.body).addClass("x-body-masked");
1917 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
1919 this.el.setStyle('zIndex', '10001');
1920 this.fireEvent('show', this);
1926 Roo.log('Modal hide?!');
1928 Roo.get(document.body).removeClass("x-body-masked");
1929 this.el.removeClass('on');
1930 this.el.addClass('fade');
1931 this.el.setStyle('display', 'none');
1932 this.fireEvent('hide', this);
1934 onButtonClick: function(btn,e)
1937 this.fireEvent('btnclick', btn.name, e);
1942 Roo.apply(Roo.bootstrap.Modal, {
1944 * Button config that displays a single OK button
1953 * Button config that displays Yes and No buttons
1969 * Button config that displays OK and Cancel buttons
1984 * Button config that displays Yes, No and Cancel buttons
2011 * @class Roo.bootstrap.Navbar
2012 * @extends Roo.bootstrap.Component
2013 * Bootstrap Navbar class
2014 * @cfg {Boolean} sidebar has side bar
2015 * @cfg {Boolean} bar is a bar?
2016 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
2017 * @cfg {String} brand what is brand
2018 * @cfg {Boolean} inverse is inverted color
2019 * @cfg {String} type (nav | pills | tabs)
2020 * @cfg {Boolean} arrangement stacked | justified
2021 * @cfg {String} align (left | right) alignment
2022 * @cfg {String} brand_href href of the brand
2023 * @cfg {Boolean} main (true|false) main nav bar? default false
2024 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
2028 * Create a new Navbar
2029 * @param {Object} config The config object
2033 Roo.bootstrap.Navbar = function(config){
2034 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2039 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2058 getAutoCreate : function(){
2063 if (this.sidebar === true) {
2071 if (this.bar === true) {
2079 cls: 'navbar-header',
2084 cls: 'navbar-toggle',
2085 'data-toggle': 'collapse',
2090 html: 'Toggle navigation'
2110 cls: 'collapse navbar-collapse'
2115 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
2117 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
2118 cfg.cls += ' navbar-' + this.position;
2119 cfg.tag = this.position == 'fixed-bottom' ? 'footer' : 'header';
2122 if (this.brand !== '') {
2125 href: this.brand_href ? this.brand_href : '#',
2126 cls: 'navbar-brand',
2134 cfg.cls += ' main-nav';
2140 } else if (this.bar === false) {
2143 Roo.log('Property \'bar\' in of Navbar must be either true or false')
2153 if (['tabs','pills'].indexOf(this.type)!==-1) {
2154 cfg.cn[0].cls += ' nav-' + this.type
2156 if (this.type!=='nav') {
2157 Roo.log('nav type must be nav/tabs/pills')
2159 cfg.cn[0].cls += ' navbar-nav'
2162 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
2163 cfg.cn[0].cls += ' nav-' + this.arrangement;
2166 if (this.align === 'right') {
2167 cfg.cn[0].cls += ' navbar-right';
2170 cfg.cls += ' navbar-inverse';
2178 initEvents :function ()
2180 //Roo.log(this.el.select('.navbar-toggle',true));
2181 this.el.select('.navbar-toggle',true).on('click', function() {
2182 // Roo.log('click');
2183 this.el.select('.navbar-collapse',true).toggleClass('in');
2191 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2193 var size = this.el.getSize();
2194 this.maskEl.setSize(size.width, size.height);
2195 this.maskEl.enableDisplayMode("block");
2204 getChildContainer : function()
2206 if (this.bar === true) {
2207 return this.el.select('.collapse',true).first();
2239 * @class Roo.bootstrap.NavGroup
2240 * @extends Roo.bootstrap.Component
2241 * Bootstrap NavGroup class
2242 * @cfg {String} align left | right
2243 * @cfg {Boolean} inverse false | true
2244 * @cfg {String} type (nav|pills|tab) default nav
2245 * @cfg {String} navId - reference Id for navbar.
2249 * Create a new nav group
2250 * @param {Object} config The config object
2253 Roo.bootstrap.NavGroup = function(config){
2254 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
2256 Roo.bootstrap.NavGroup.register(this);
2260 * Fires when the active item changes
2261 * @param {Roo.bootstrap.NavGroup} this
2262 * @param {Roo.bootstrap.Navbar.Item} item The item selected
2263 * @param {Roo.bootstrap.Navbar.Item} item The previously selected item
2270 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
2281 getAutoCreate : function()
2283 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
2290 if (['tabs','pills'].indexOf(this.type)!==-1) {
2291 cfg.cls += ' nav-' + this.type
2293 if (this.type!=='nav') {
2294 Roo.log('nav type must be nav/tabs/pills')
2296 cfg.cls += ' navbar-nav'
2299 if (this.parent().sidebar === true) {
2302 cls: 'dashboard-menu'
2308 if (this.form === true) {
2314 if (this.align === 'right') {
2315 cfg.cls += ' navbar-right';
2317 cfg.cls += ' navbar-left';
2321 if (this.align === 'right') {
2322 cfg.cls += ' navbar-right';
2326 cfg.cls += ' navbar-inverse';
2334 setActiveItem : function(item)
2337 Roo.each(this.navItems, function(v){
2342 v.setActive(false, true);
2349 item.setActive(true, true);
2350 this.fireEvent('changed', this, item, prev);
2356 register : function(item)
2358 this.navItems.push( item);
2359 item.navId = this.navId;
2362 getNavItem: function(tabId)
2365 Roo.each(this.navItems, function(e) {
2366 if (e.tabId == tabId) {
2378 Roo.apply(Roo.bootstrap.NavGroup, {
2382 register : function(navgrp)
2384 this.groups[navgrp.navId] = navgrp;
2387 get: function(navId) {
2388 return this.groups[navId];
2403 * @class Roo.bootstrap.Navbar.Item
2404 * @extends Roo.bootstrap.Component
2405 * Bootstrap Navbar.Button class
2406 * @cfg {String} href link to
2407 * @cfg {String} html content of button
2408 * @cfg {String} badge text inside badge
2409 * @cfg {String} glyphicon name of glyphicon
2410 * @cfg {String} icon name of font awesome icon
2411 * @cfg {Boolean} active Is item active
2412 * @cfg {Boolean} preventDefault (true | false) default false
2413 * @cfg {String} tabId the tab that this item activates.
2416 * Create a new Navbar Button
2417 * @param {Object} config The config object
2419 Roo.bootstrap.Navbar.Item = function(config){
2420 Roo.bootstrap.Navbar.Item.superclass.constructor.call(this, config);
2425 * The raw click event for the entire grid.
2426 * @param {Roo.EventObject} e
2431 * Fires when the active item active state changes
2432 * @param {Roo.bootstrap.Navbar.Item} this
2433 * @param {boolean} state the new state
2441 Roo.extend(Roo.bootstrap.Navbar.Item, Roo.bootstrap.Component, {
2449 preventDefault : false,
2452 getAutoCreate : function(){
2454 var cfg = Roo.apply({}, Roo.bootstrap.Navbar.Item.superclass.getAutoCreate.call(this));
2456 if (this.parent().parent().sidebar === true) {
2469 cfg.cn[0].html = this.html;
2473 this.cls += ' active';
2477 cfg.cn[0].cls += ' dropdown-toggle';
2478 cfg.cn[0].html = (cfg.cn[0].html || this.html) + '<span class="glyphicon glyphicon-chevron-down"></span>';
2482 cfg.cn[0].tag = 'a',
2483 cfg.cn[0].href = this.href;
2486 if (this.glyphicon) {
2487 cfg.cn[0].html = '<i class="glyphicon glyphicon-'+this.glyphicon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
2491 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
2503 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
2513 if (this.glyphicon) {
2514 if(cfg.html){cfg.html = ' ' + this.html};
2518 cls: 'glyphicon glyphicon-' + this.glyphicon
2523 cfg.cn[0].html = this.html || cfg.cn[0].html ;
2528 cfg.cn[0].html += " <span class='caret'></span>";
2529 //}else if (!this.href) {
2530 // cfg.cn[0].tag='p';
2531 // cfg.cn[0].cls='navbar-text';
2534 cfg.cn[0].href=this.href||'#';
2535 cfg.cn[0].html=this.html;
2538 if (this.badge !== '') {
2541 cfg.cn[0].html + ' ',
2552 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
2557 initEvents: function() {
2558 // Roo.log('init events?');
2559 // Roo.log(this.el.dom);
2560 this.el.select('a',true).on('click', this.onClick, this);
2561 // at this point parent should be available..
2562 this.parent().register(this);
2565 onClick : function(e)
2567 if(this.preventDefault){
2571 if(this.fireEvent('click', this, e) === false){
2575 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
2576 if (typeof(this.parent().setActiveItem) !== 'undefined') {
2577 this.parent().setActiveItem(this);
2585 isActive: function () {
2588 setActive : function(state, fire)
2590 this.active = state;
2592 this.el.removeClass('active');
2593 } else if (!this.el.hasClass('active')) {
2594 this.el.addClass('active');
2597 this.fireEvent('changed', this, state);
2602 // this should not be here...
2615 * @class Roo.bootstrap.Row
2616 * @extends Roo.bootstrap.Component
2617 * Bootstrap Row class (contains columns...)
2621 * @param {Object} config The config object
2624 Roo.bootstrap.Row = function(config){
2625 Roo.bootstrap.Row.superclass.constructor.call(this, config);
2628 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
2630 getAutoCreate : function(){
2649 * @class Roo.bootstrap.Element
2650 * @extends Roo.bootstrap.Component
2651 * Bootstrap Element class
2652 * @cfg {String} html contents of the element
2653 * @cfg {String} tag tag of the element
2654 * @cfg {String} cls class of the element
2657 * Create a new Element
2658 * @param {Object} config The config object
2661 Roo.bootstrap.Element = function(config){
2662 Roo.bootstrap.Element.superclass.constructor.call(this, config);
2665 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
2672 getAutoCreate : function(){
2697 * @class Roo.bootstrap.Pagination
2698 * @extends Roo.bootstrap.Component
2699 * Bootstrap Pagination class
2700 * @cfg {String} size xs | sm | md | lg
2701 * @cfg {Boolean} inverse false | true
2704 * Create a new Pagination
2705 * @param {Object} config The config object
2708 Roo.bootstrap.Pagination = function(config){
2709 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
2712 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
2718 getAutoCreate : function(){
2724 cfg.cls += ' inverse';
2730 cfg.cls += " " + this.cls;
2748 * @class Roo.bootstrap.PaginationItem
2749 * @extends Roo.bootstrap.Component
2750 * Bootstrap PaginationItem class
2751 * @cfg {String} html text
2752 * @cfg {String} href the link
2753 * @cfg {Boolean} preventDefault (true | false) default true
2754 * @cfg {Boolean} active (true | false) default false
2758 * Create a new PaginationItem
2759 * @param {Object} config The config object
2763 Roo.bootstrap.PaginationItem = function(config){
2764 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
2769 * The raw click event for the entire grid.
2770 * @param {Roo.EventObject} e
2776 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
2780 preventDefault: true,
2784 getAutoCreate : function(){
2790 href : this.href ? this.href : '#',
2791 html : this.html ? this.html : ''
2801 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
2807 initEvents: function() {
2809 this.el.on('click', this.onClick, this);
2812 onClick : function(e)
2814 Roo.log('PaginationItem on click ');
2815 if(this.preventDefault){
2819 this.fireEvent('click', this, e);
2835 * @class Roo.bootstrap.Slider
2836 * @extends Roo.bootstrap.Component
2837 * Bootstrap Slider class
2840 * Create a new Slider
2841 * @param {Object} config The config object
2844 Roo.bootstrap.Slider = function(config){
2845 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
2848 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
2850 getAutoCreate : function(){
2854 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
2858 cls: 'ui-slider-handle ui-state-default ui-corner-all'
2876 * @class Roo.bootstrap.Table
2877 * @extends Roo.bootstrap.Component
2878 * Bootstrap Table class
2879 * @cfg {String} cls table class
2880 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
2881 * @cfg {String} bgcolor Specifies the background color for a table
2882 * @cfg {Number} border Specifies whether the table cells should have borders or not
2883 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
2884 * @cfg {Number} cellspacing Specifies the space between cells
2885 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
2886 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
2887 * @cfg {String} sortable Specifies that the table should be sortable
2888 * @cfg {String} summary Specifies a summary of the content of a table
2889 * @cfg {Number} width Specifies the width of a table
2891 * @cfg {boolean} striped Should the rows be alternative striped
2892 * @cfg {boolean} bordered Add borders to the table
2893 * @cfg {boolean} hover Add hover highlighting
2894 * @cfg {boolean} condensed Format condensed
2895 * @cfg {boolean} responsive Format condensed
2901 * Create a new Table
2902 * @param {Object} config The config object
2905 Roo.bootstrap.Table = function(config){
2906 Roo.bootstrap.Table.superclass.constructor.call(this, config);
2909 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
2910 this.sm = this.selModel;
2911 this.sm.xmodule = this.xmodule || false;
2913 if (this.cm && typeof(this.cm.config) == 'undefined') {
2914 this.colModel = new Roo.bootstrap.Table.ColumnModel(this.cm);
2915 this.cm = this.colModel;
2916 this.cm.xmodule = this.xmodule || false;
2919 this.store= Roo.factory(this.store, Roo.data);
2920 this.ds = this.store;
2921 this.ds.xmodule = this.xmodule || false;
2926 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
2948 getAutoCreate : function(){
2949 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
2958 cfg.cls += ' table-striped';
2961 cfg.cls += ' table-hover';
2963 if (this.bordered) {
2964 cfg.cls += ' table-bordered';
2966 if (this.condensed) {
2967 cfg.cls += ' table-condensed';
2969 if (this.responsive) {
2970 cfg.cls += ' table-responsive';
2977 cfg.cls+= ' ' +this.cls;
2980 // this lot should be simplifed...
2983 cfg.align=this.align;
2986 cfg.bgcolor=this.bgcolor;
2989 cfg.border=this.border;
2991 if (this.cellpadding) {
2992 cfg.cellpadding=this.cellpadding;
2994 if (this.cellspacing) {
2995 cfg.cellspacing=this.cellspacing;
2998 cfg.frame=this.frame;
3001 cfg.rules=this.rules;
3003 if (this.sortable) {
3004 cfg.sortable=this.sortable;
3007 cfg.summary=this.summary;
3010 cfg.width=this.width;
3013 if(this.store || this.cm){
3014 cfg.cn.push(this.renderHeader());
3015 cfg.cn.push(this.renderBody());
3016 cfg.cn.push(this.renderFooter());
3018 cfg.cls+= ' TableGrid';
3024 // initTableGrid : function()
3033 // var cm = this.cm;
3035 // for(var i = 0, len = cm.getColumnCount(); i < len; i++){
3038 // html: cm.getColumnHeader(i)
3042 // cfg.push(header);
3049 initEvents : function()
3051 if(!this.store || !this.cm){
3055 Roo.log('initEvents with ds!!!!');
3059 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
3060 e.on('click', _this.sort, _this);
3062 // this.maskEl = Roo.DomHelper.append(this.el.select('.TableGrid', true).first(), {tag: "div", cls:"x-dlg-mask"}, true);
3063 // this.maskEl.enableDisplayMode("block");
3064 // this.maskEl.show();
3066 this.store.on('load', this.onLoad, this);
3067 this.store.on('beforeload', this.onBeforeLoad, this);
3075 sort : function(e,el)
3077 var col = Roo.get(el)
3079 if(!col.hasClass('sortable')){
3083 var sort = col.attr('sort');
3086 if(col.hasClass('glyphicon-arrow-up')){
3090 this.store.sortInfo = {field : sort, direction : dir};
3095 renderHeader : function()
3104 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
3106 var config = cm.config[i];
3110 html: cm.getColumnHeader(i)
3113 if(typeof(config.dataIndex) != 'undefined'){
3114 c.sort = config.dataIndex;
3117 if(typeof(config.sortable) != 'undefined' && config.sortable){
3121 if(typeof(config.width) != 'undefined'){
3122 c.style = 'width:' + config.width + 'px';
3131 renderBody : function()
3141 renderFooter : function()
3153 Roo.log('ds onload');
3158 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
3159 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
3161 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
3162 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
3165 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
3166 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
3170 var tbody = this.el.select('tbody', true).first();
3174 if(this.store.getCount() > 0){
3175 this.store.data.each(function(d){
3181 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
3182 var renderer = cm.getRenderer(i);
3183 var config = cm.config[i];
3187 if(typeof(renderer) !== 'undefined'){
3188 value = renderer(d.data[cm.getDataIndex(i)], false, d);
3191 if(typeof(value) === 'object'){
3201 html: (typeof(value) === 'object') ? '' : value
3204 if(typeof(config.width) != 'undefined'){
3205 td.style = 'width:' + config.width + 'px';
3212 tbody.createChild(row);
3220 Roo.each(renders, function(r){
3221 _this.renderColumn(r);
3225 // if(this.loadMask){
3226 // this.maskEl.hide();
3230 onBeforeLoad : function()
3232 Roo.log('ds onBeforeLoad');
3236 // if(this.loadMask){
3237 // this.maskEl.show();
3243 this.el.select('tbody', true).first().dom.innerHTML = '';
3246 getSelectionModel : function(){
3248 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
3250 return this.selModel;
3253 renderColumn : function(r)
3256 r.cfg.render(Roo.get(r.id));
3259 Roo.each(r.cfg.cn, function(c){
3264 _this.renderColumn(child);
3281 * @class Roo.bootstrap.TableCell
3282 * @extends Roo.bootstrap.Component
3283 * Bootstrap TableCell class
3284 * @cfg {String} html cell contain text
3285 * @cfg {String} cls cell class
3286 * @cfg {String} tag cell tag (td|th) default td
3287 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
3288 * @cfg {String} align Aligns the content in a cell
3289 * @cfg {String} axis Categorizes cells
3290 * @cfg {String} bgcolor Specifies the background color of a cell
3291 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
3292 * @cfg {Number} colspan Specifies the number of columns a cell should span
3293 * @cfg {String} headers Specifies one or more header cells a cell is related to
3294 * @cfg {Number} height Sets the height of a cell
3295 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
3296 * @cfg {Number} rowspan Sets the number of rows a cell should span
3297 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
3298 * @cfg {String} valign Vertical aligns the content in a cell
3299 * @cfg {Number} width Specifies the width of a cell
3302 * Create a new TableCell
3303 * @param {Object} config The config object
3306 Roo.bootstrap.TableCell = function(config){
3307 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
3310 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
3330 getAutoCreate : function(){
3331 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
3351 cfg.align=this.align
3357 cfg.bgcolor=this.bgcolor
3360 cfg.charoff=this.charoff
3363 cfg.colspan=this.colspan
3366 cfg.headers=this.headers
3369 cfg.height=this.height
3372 cfg.nowrap=this.nowrap
3375 cfg.rowspan=this.rowspan
3378 cfg.scope=this.scope
3381 cfg.valign=this.valign
3384 cfg.width=this.width
3403 * @class Roo.bootstrap.TableRow
3404 * @extends Roo.bootstrap.Component
3405 * Bootstrap TableRow class
3406 * @cfg {String} cls row class
3407 * @cfg {String} align Aligns the content in a table row
3408 * @cfg {String} bgcolor Specifies a background color for a table row
3409 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
3410 * @cfg {String} valign Vertical aligns the content in a table row
3413 * Create a new TableRow
3414 * @param {Object} config The config object
3417 Roo.bootstrap.TableRow = function(config){
3418 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
3421 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
3429 getAutoCreate : function(){
3430 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
3440 cfg.align = this.align;
3443 cfg.bgcolor = this.bgcolor;
3446 cfg.charoff = this.charoff;
3449 cfg.valign = this.valign;
3467 * @class Roo.bootstrap.TableBody
3468 * @extends Roo.bootstrap.Component
3469 * Bootstrap TableBody class
3470 * @cfg {String} cls element class
3471 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
3472 * @cfg {String} align Aligns the content inside the element
3473 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
3474 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
3477 * Create a new TableBody
3478 * @param {Object} config The config object
3481 Roo.bootstrap.TableBody = function(config){
3482 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
3485 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
3493 getAutoCreate : function(){
3494 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
3508 cfg.align = this.align;
3511 cfg.charoff = this.charoff;
3514 cfg.valign = this.valign;
3521 // initEvents : function()
3528 // this.store = Roo.factory(this.store, Roo.data);
3529 // this.store.on('load', this.onLoad, this);
3531 // this.store.load();
3535 // onLoad: function ()
3537 // this.fireEvent('load', this);
3547 * Ext JS Library 1.1.1
3548 * Copyright(c) 2006-2007, Ext JS, LLC.
3550 * Originally Released Under LGPL - original licence link has changed is not relivant.
3553 * <script type="text/javascript">
3556 // as we use this in bootstrap.
3557 Roo.namespace('Roo.form');
3559 * @class Roo.form.Action
3560 * Internal Class used to handle form actions
3562 * @param {Roo.form.BasicForm} el The form element or its id
3563 * @param {Object} config Configuration options
3568 // define the action interface
3569 Roo.form.Action = function(form, options){
3571 this.options = options || {};
3574 * Client Validation Failed
3577 Roo.form.Action.CLIENT_INVALID = 'client';
3579 * Server Validation Failed
3582 Roo.form.Action.SERVER_INVALID = 'server';
3584 * Connect to Server Failed
3587 Roo.form.Action.CONNECT_FAILURE = 'connect';
3589 * Reading Data from Server Failed
3592 Roo.form.Action.LOAD_FAILURE = 'load';
3594 Roo.form.Action.prototype = {
3596 failureType : undefined,
3597 response : undefined,
3601 run : function(options){
3606 success : function(response){
3611 handleResponse : function(response){
3615 // default connection failure
3616 failure : function(response){
3618 this.response = response;
3619 this.failureType = Roo.form.Action.CONNECT_FAILURE;
3620 this.form.afterAction(this, false);
3623 processResponse : function(response){
3624 this.response = response;
3625 if(!response.responseText){
3628 this.result = this.handleResponse(response);
3632 // utility functions used internally
3633 getUrl : function(appendParams){
3634 var url = this.options.url || this.form.url || this.form.el.dom.action;
3636 var p = this.getParams();
3638 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
3644 getMethod : function(){
3645 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
3648 getParams : function(){
3649 var bp = this.form.baseParams;
3650 var p = this.options.params;
3652 if(typeof p == "object"){
3653 p = Roo.urlEncode(Roo.applyIf(p, bp));
3654 }else if(typeof p == 'string' && bp){
3655 p += '&' + Roo.urlEncode(bp);
3658 p = Roo.urlEncode(bp);
3663 createCallback : function(){
3665 success: this.success,
3666 failure: this.failure,
3668 timeout: (this.form.timeout*1000),
3669 upload: this.form.fileUpload ? this.success : undefined
3674 Roo.form.Action.Submit = function(form, options){
3675 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
3678 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
3681 haveProgress : false,
3682 uploadComplete : false,
3684 // uploadProgress indicator.
3685 uploadProgress : function()
3687 if (!this.form.progressUrl) {
3691 if (!this.haveProgress) {
3692 Roo.MessageBox.progress("Uploading", "Uploading");
3694 if (this.uploadComplete) {
3695 Roo.MessageBox.hide();
3699 this.haveProgress = true;
3701 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
3703 var c = new Roo.data.Connection();
3705 url : this.form.progressUrl,
3710 success : function(req){
3711 //console.log(data);
3715 rdata = Roo.decode(req.responseText)
3717 Roo.log("Invalid data from server..");
3721 if (!rdata || !rdata.success) {
3723 Roo.MessageBox.alert(Roo.encode(rdata));
3726 var data = rdata.data;
3728 if (this.uploadComplete) {
3729 Roo.MessageBox.hide();
3734 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
3735 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
3738 this.uploadProgress.defer(2000,this);
3741 failure: function(data) {
3742 Roo.log('progress url failed ');
3753 // run get Values on the form, so it syncs any secondary forms.
3754 this.form.getValues();
3756 var o = this.options;
3757 var method = this.getMethod();
3758 var isPost = method == 'POST';
3759 if(o.clientValidation === false || this.form.isValid()){
3761 if (this.form.progressUrl) {
3762 this.form.findField('UPLOAD_IDENTIFIER').setValue(
3763 (new Date() * 1) + '' + Math.random());
3768 Roo.Ajax.request(Roo.apply(this.createCallback(), {
3769 form:this.form.el.dom,
3770 url:this.getUrl(!isPost),
3772 params:isPost ? this.getParams() : null,
3773 isUpload: this.form.fileUpload
3776 this.uploadProgress();
3778 }else if (o.clientValidation !== false){ // client validation failed
3779 this.failureType = Roo.form.Action.CLIENT_INVALID;
3780 this.form.afterAction(this, false);
3784 success : function(response)
3786 this.uploadComplete= true;
3787 if (this.haveProgress) {
3788 Roo.MessageBox.hide();
3792 var result = this.processResponse(response);
3793 if(result === true || result.success){
3794 this.form.afterAction(this, true);
3798 this.form.markInvalid(result.errors);
3799 this.failureType = Roo.form.Action.SERVER_INVALID;
3801 this.form.afterAction(this, false);
3803 failure : function(response)
3805 this.uploadComplete= true;
3806 if (this.haveProgress) {
3807 Roo.MessageBox.hide();
3810 this.response = response;
3811 this.failureType = Roo.form.Action.CONNECT_FAILURE;
3812 this.form.afterAction(this, false);
3815 handleResponse : function(response){
3816 if(this.form.errorReader){
3817 var rs = this.form.errorReader.read(response);
3820 for(var i = 0, len = rs.records.length; i < len; i++) {
3821 var r = rs.records[i];
3825 if(errors.length < 1){
3829 success : rs.success,
3835 ret = Roo.decode(response.responseText);
3839 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
3849 Roo.form.Action.Load = function(form, options){
3850 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
3851 this.reader = this.form.reader;
3854 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
3859 Roo.Ajax.request(Roo.apply(
3860 this.createCallback(), {
3861 method:this.getMethod(),
3862 url:this.getUrl(false),
3863 params:this.getParams()
3867 success : function(response){
3869 var result = this.processResponse(response);
3870 if(result === true || !result.success || !result.data){
3871 this.failureType = Roo.form.Action.LOAD_FAILURE;
3872 this.form.afterAction(this, false);
3875 this.form.clearInvalid();
3876 this.form.setValues(result.data);
3877 this.form.afterAction(this, true);
3880 handleResponse : function(response){
3881 if(this.form.reader){
3882 var rs = this.form.reader.read(response);
3883 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
3885 success : rs.success,
3889 return Roo.decode(response.responseText);
3893 Roo.form.Action.ACTION_TYPES = {
3894 'load' : Roo.form.Action.Load,
3895 'submit' : Roo.form.Action.Submit
3904 * @class Roo.bootstrap.Form
3905 * @extends Roo.bootstrap.Component
3906 * Bootstrap Form class
3907 * @cfg {String} method GET | POST (default POST)
3908 * @cfg {String} labelAlign top | left (default top)
3909 * @cfg {String} align left | right - for navbars
3914 * @param {Object} config The config object
3918 Roo.bootstrap.Form = function(config){
3919 Roo.bootstrap.Form.superclass.constructor.call(this, config);
3922 * @event clientvalidation
3923 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
3924 * @param {Form} this
3925 * @param {Boolean} valid true if the form has passed client-side validation
3927 clientvalidation: true,
3929 * @event beforeaction
3930 * Fires before any action is performed. Return false to cancel the action.
3931 * @param {Form} this
3932 * @param {Action} action The action to be performed
3936 * @event actionfailed
3937 * Fires when an action fails.
3938 * @param {Form} this
3939 * @param {Action} action The action that failed
3941 actionfailed : true,
3943 * @event actioncomplete
3944 * Fires when an action is completed.
3945 * @param {Form} this
3946 * @param {Action} action The action that completed
3948 actioncomplete : true
3953 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
3956 * @cfg {String} method
3957 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
3962 * The URL to use for form actions if one isn't supplied in the action options.
3965 * @cfg {Boolean} fileUpload
3966 * Set to true if this form is a file upload.
3970 * @cfg {Object} baseParams
3971 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
3975 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
3979 * @cfg {Sting} align (left|right) for navbar forms
3984 activeAction : null,
3987 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
3988 * element by passing it or its id or mask the form itself by passing in true.
3991 waitMsgTarget : false,
3996 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
3997 * element by passing it or its id or mask the form itself by passing in true.
4001 getAutoCreate : function(){
4005 method : this.method || 'POST',
4006 id : this.id || Roo.id(),
4009 if (this.parent().xtype.match(/^Nav/)) {
4010 cfg.cls = 'navbar-form navbar-' + this.align;
4014 if (this.labelAlign == 'left' ) {
4015 cfg.cls += ' form-horizontal';
4021 initEvents : function()
4023 this.el.on('submit', this.onSubmit, this);
4028 onSubmit : function(e){
4033 * Returns true if client-side validation on the form is successful.
4036 isValid : function(){
4037 var items = this.getItems();
4039 items.each(function(f){
4048 * Returns true if any fields in this form have changed since their original load.
4051 isDirty : function(){
4053 var items = this.getItems();
4054 items.each(function(f){
4064 * Performs a predefined action (submit or load) or custom actions you define on this form.
4065 * @param {String} actionName The name of the action type
4066 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
4067 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
4068 * accept other config options):
4070 Property Type Description
4071 ---------------- --------------- ----------------------------------------------------------------------------------
4072 url String The url for the action (defaults to the form's url)
4073 method String The form method to use (defaults to the form's method, or POST if not defined)
4074 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
4075 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
4076 validate the form on the client (defaults to false)
4078 * @return {BasicForm} this
4080 doAction : function(action, options){
4081 if(typeof action == 'string'){
4082 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
4084 if(this.fireEvent('beforeaction', this, action) !== false){
4085 this.beforeAction(action);
4086 action.run.defer(100, action);
4092 beforeAction : function(action){
4093 var o = action.options;
4095 // not really supported yet.. ??
4097 //if(this.waitMsgTarget === true){
4098 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
4099 //}else if(this.waitMsgTarget){
4100 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
4101 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
4103 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
4109 afterAction : function(action, success){
4110 this.activeAction = null;
4111 var o = action.options;
4113 //if(this.waitMsgTarget === true){
4115 //}else if(this.waitMsgTarget){
4116 // this.waitMsgTarget.unmask();
4118 // Roo.MessageBox.updateProgress(1);
4119 // Roo.MessageBox.hide();
4126 Roo.callback(o.success, o.scope, [this, action]);
4127 this.fireEvent('actioncomplete', this, action);
4131 // failure condition..
4132 // we have a scenario where updates need confirming.
4133 // eg. if a locking scenario exists..
4134 // we look for { errors : { needs_confirm : true }} in the response.
4136 (typeof(action.result) != 'undefined') &&
4137 (typeof(action.result.errors) != 'undefined') &&
4138 (typeof(action.result.errors.needs_confirm) != 'undefined')
4141 Roo.log("not supported yet");
4144 Roo.MessageBox.confirm(
4145 "Change requires confirmation",
4146 action.result.errorMsg,
4151 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
4161 Roo.callback(o.failure, o.scope, [this, action]);
4162 // show an error message if no failed handler is set..
4163 if (!this.hasListener('actionfailed')) {
4164 Roo.log("need to add dialog support");
4166 Roo.MessageBox.alert("Error",
4167 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
4168 action.result.errorMsg :
4169 "Saving Failed, please check your entries or try again"
4174 this.fireEvent('actionfailed', this, action);
4179 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
4180 * @param {String} id The value to search for
4183 findField : function(id){
4184 var items = this.getItems();
4185 var field = items.get(id);
4187 items.each(function(f){
4188 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
4195 return field || null;
4198 * Mark fields in this form invalid in bulk.
4199 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
4200 * @return {BasicForm} this
4202 markInvalid : function(errors){
4203 if(errors instanceof Array){
4204 for(var i = 0, len = errors.length; i < len; i++){
4205 var fieldError = errors[i];
4206 var f = this.findField(fieldError.id);
4208 f.markInvalid(fieldError.msg);
4214 if(typeof errors[id] != 'function' && (field = this.findField(id))){
4215 field.markInvalid(errors[id]);
4219 //Roo.each(this.childForms || [], function (f) {
4220 // f.markInvalid(errors);
4227 * Set values for fields in this form in bulk.
4228 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
4229 * @return {BasicForm} this
4231 setValues : function(values){
4232 if(values instanceof Array){ // array of objects
4233 for(var i = 0, len = values.length; i < len; i++){
4235 var f = this.findField(v.id);
4237 f.setValue(v.value);
4238 if(this.trackResetOnLoad){
4239 f.originalValue = f.getValue();
4243 }else{ // object hash
4246 if(typeof values[id] != 'function' && (field = this.findField(id))){
4248 if (field.setFromData &&
4250 field.displayField &&
4251 // combos' with local stores can
4252 // be queried via setValue()
4253 // to set their value..
4254 (field.store && !field.store.isLocal)
4258 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
4259 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
4260 field.setFromData(sd);
4263 field.setValue(values[id]);
4267 if(this.trackResetOnLoad){
4268 field.originalValue = field.getValue();
4274 //Roo.each(this.childForms || [], function (f) {
4275 // f.setValues(values);
4282 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
4283 * they are returned as an array.
4284 * @param {Boolean} asString
4287 getValues : function(asString){
4288 //if (this.childForms) {
4289 // copy values from the child forms
4290 // Roo.each(this.childForms, function (f) {
4291 // this.setValues(f.getValues());
4297 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
4298 if(asString === true){
4301 return Roo.urlDecode(fs);
4305 * Returns the fields in this form as an object with key/value pairs.
4306 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
4309 getFieldValues : function(with_hidden)
4311 var items = this.getItems();
4313 items.each(function(f){
4317 var v = f.getValue();
4318 if (f.inputType =='radio') {
4319 if (typeof(ret[f.getName()]) == 'undefined') {
4320 ret[f.getName()] = ''; // empty..
4323 if (!f.el.dom.checked) {
4331 // not sure if this supported any more..
4332 if ((typeof(v) == 'object') && f.getRawValue) {
4333 v = f.getRawValue() ; // dates..
4335 // combo boxes where name != hiddenName...
4336 if (f.name != f.getName()) {
4337 ret[f.name] = f.getRawValue();
4339 ret[f.getName()] = v;
4346 * Clears all invalid messages in this form.
4347 * @return {BasicForm} this
4349 clearInvalid : function(){
4350 var items = this.getItems();
4352 items.each(function(f){
4363 * @return {BasicForm} this
4366 var items = this.getItems();
4367 items.each(function(f){
4371 Roo.each(this.childForms || [], function (f) {
4378 getItems : function()
4380 var r=new Roo.util.MixedCollection(false, function(o){
4381 return o.id || (o.id = Roo.id());
4383 var iter = function(el) {
4390 Roo.each(el.items,function(e) {
4409 * Ext JS Library 1.1.1
4410 * Copyright(c) 2006-2007, Ext JS, LLC.
4412 * Originally Released Under LGPL - original licence link has changed is not relivant.
4415 * <script type="text/javascript">
4418 * @class Roo.form.VTypes
4419 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
4422 Roo.form.VTypes = function(){
4423 // closure these in so they are only created once.
4424 var alpha = /^[a-zA-Z_]+$/;
4425 var alphanum = /^[a-zA-Z0-9_]+$/;
4426 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
4427 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
4429 // All these messages and functions are configurable
4432 * The function used to validate email addresses
4433 * @param {String} value The email address
4435 'email' : function(v){
4436 return email.test(v);
4439 * The error text to display when the email validation function returns false
4442 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
4444 * The keystroke filter mask to be applied on email input
4447 'emailMask' : /[a-z0-9_\.\-@]/i,
4450 * The function used to validate URLs
4451 * @param {String} value The URL
4453 'url' : function(v){
4457 * The error text to display when the url validation function returns false
4460 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
4463 * The function used to validate alpha values
4464 * @param {String} value The value
4466 'alpha' : function(v){
4467 return alpha.test(v);
4470 * The error text to display when the alpha validation function returns false
4473 'alphaText' : 'This field should only contain letters and _',
4475 * The keystroke filter mask to be applied on alpha input
4478 'alphaMask' : /[a-z_]/i,
4481 * The function used to validate alphanumeric values
4482 * @param {String} value The value
4484 'alphanum' : function(v){
4485 return alphanum.test(v);
4488 * The error text to display when the alphanumeric validation function returns false
4491 'alphanumText' : 'This field should only contain letters, numbers and _',
4493 * The keystroke filter mask to be applied on alphanumeric input
4496 'alphanumMask' : /[a-z0-9_]/i
4506 * @class Roo.bootstrap.Input
4507 * @extends Roo.bootstrap.Component
4508 * Bootstrap Input class
4509 * @cfg {Boolean} disabled is it disabled
4510 * @cfg {String} fieldLabel - the label associated
4511 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
4512 * @cfg {String} name name of the input
4513 * @cfg {string} fieldLabel - the label associated
4514 * @cfg {string} inputType - input / file submit ...
4515 * @cfg {string} placeholder - placeholder to put in text.
4516 * @cfg {string} before - input group add on before
4517 * @cfg {string} after - input group add on after
4518 * @cfg {string} size - (lg|sm) or leave empty..
4519 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
4520 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
4521 * @cfg {Number} md colspan out of 12 for computer-sized screens
4522 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
4523 * @cfg {string} value default value of the input
4524 * @cfg {Number} labelWidth set the width of label (0-12)
4525 * @cfg {String} labelAlign (top|left)
4526 * @cfg {Boolean} readOnly Specifies that the field should be read-only
4530 * Create a new Input
4531 * @param {Object} config The config object
4534 Roo.bootstrap.Input = function(config){
4535 Roo.bootstrap.Input.superclass.constructor.call(this, config);
4540 * Fires when this field receives input focus.
4541 * @param {Roo.form.Field} this
4546 * Fires when this field loses input focus.
4547 * @param {Roo.form.Field} this
4552 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
4553 * {@link Roo.EventObject#getKey} to determine which key was pressed.
4554 * @param {Roo.form.Field} this
4555 * @param {Roo.EventObject} e The event object
4560 * Fires just before the field blurs if the field value has changed.
4561 * @param {Roo.form.Field} this
4562 * @param {Mixed} newValue The new value
4563 * @param {Mixed} oldValue The original value
4568 * Fires after the field has been marked as invalid.
4569 * @param {Roo.form.Field} this
4570 * @param {String} msg The validation message
4575 * Fires after the field has been validated with no errors.
4576 * @param {Roo.form.Field} this
4581 * Fires after the key up
4582 * @param {Roo.form.Field} this
4583 * @param {Roo.EventObject} e The event Object
4589 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
4591 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
4592 automatic validation (defaults to "keyup").
4594 validationEvent : "keyup",
4596 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
4598 validateOnBlur : true,
4600 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
4602 validationDelay : 250,
4604 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
4606 focusClass : "x-form-focus", // not needed???
4610 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
4612 invalidClass : "has-error",
4615 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
4617 selectOnFocus : false,
4620 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
4624 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
4629 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
4631 disableKeyFilter : false,
4634 * @cfg {Boolean} disabled True to disable the field (defaults to false).
4638 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
4642 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
4644 blankText : "This field is required",
4647 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
4651 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
4653 maxLength : Number.MAX_VALUE,
4655 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
4657 minLengthText : "The minimum length for this field is {0}",
4659 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
4661 maxLengthText : "The maximum length for this field is {0}",
4665 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
4666 * If available, this function will be called only after the basic validators all return true, and will be passed the
4667 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
4671 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
4672 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
4673 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
4677 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
4700 parentLabelAlign : function()
4703 while (parent.parent()) {
4704 parent = parent.parent();
4705 if (typeof(parent.labelAlign) !='undefined') {
4706 return parent.labelAlign;
4713 getAutoCreate : function(){
4715 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
4721 if(this.inputType != 'hidden'){
4722 cfg.cls = 'form-group' //input-group
4728 type : this.inputType,
4730 cls : 'form-control',
4731 placeholder : this.placeholder || ''
4735 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
4736 input.maxLength = this.maxLength;
4739 if (this.disabled) {
4740 input.disabled=true;
4743 if (this.readOnly) {
4744 input.readonly=true;
4748 input.name = this.name;
4751 input.cls += ' input-' + this.size;
4754 ['xs','sm','md','lg'].map(function(size){
4755 if (settings[size]) {
4756 cfg.cls += ' col-' + size + '-' + settings[size];
4760 var inputblock = input;
4762 if (this.before || this.after) {
4765 cls : 'input-group',
4769 inputblock.cn.push({
4771 cls : 'input-group-addon',
4775 inputblock.cn.push(input);
4777 inputblock.cn.push({
4779 cls : 'input-group-addon',
4786 if (align ==='left' && this.fieldLabel.length) {
4787 Roo.log("left and has label");
4793 cls : 'control-label col-sm-' + this.labelWidth,
4794 html : this.fieldLabel
4798 cls : "col-sm-" + (12 - this.labelWidth),
4805 } else if ( this.fieldLabel.length) {
4811 //cls : 'input-group-addon',
4812 html : this.fieldLabel
4822 Roo.log(" no label && no align");
4831 Roo.log('input-parentType: ' + this.parentType);
4833 if (this.parentType === 'Navbar' && this.parent().bar) {
4834 cfg.cls += ' navbar-form';
4842 * return the real input element.
4844 inputEl: function ()
4846 return this.el.select('input.form-control',true).first();
4848 setDisabled : function(v)
4850 var i = this.inputEl().dom;
4852 i.removeAttribute('disabled');
4856 i.setAttribute('disabled','true');
4858 initEvents : function()
4861 this.inputEl().on("keydown" , this.fireKey, this);
4862 this.inputEl().on("focus", this.onFocus, this);
4863 this.inputEl().on("blur", this.onBlur, this);
4865 this.inputEl().relayEvent('keyup', this);
4867 // reference to original value for reset
4868 this.originalValue = this.getValue();
4869 //Roo.form.TextField.superclass.initEvents.call(this);
4870 if(this.validationEvent == 'keyup'){
4871 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
4872 this.inputEl().on('keyup', this.filterValidation, this);
4874 else if(this.validationEvent !== false){
4875 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
4878 if(this.selectOnFocus){
4879 this.on("focus", this.preFocus, this);
4882 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
4883 this.inputEl().on("keypress", this.filterKeys, this);
4886 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
4887 this.el.on("click", this.autoSize, this);
4890 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
4891 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
4895 filterValidation : function(e){
4896 if(!e.isNavKeyPress()){
4897 this.validationTask.delay(this.validationDelay);
4901 * Validates the field value
4902 * @return {Boolean} True if the value is valid, else false
4904 validate : function(){
4905 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
4906 if(this.disabled || this.validateValue(this.getRawValue())){
4907 this.clearInvalid();
4915 * Validates a value according to the field's validation rules and marks the field as invalid
4916 * if the validation fails
4917 * @param {Mixed} value The value to validate
4918 * @return {Boolean} True if the value is valid, else false
4920 validateValue : function(value){
4921 if(value.length < 1) { // if it's blank
4922 if(this.allowBlank){
4923 this.clearInvalid();
4926 this.markInvalid(this.blankText);
4930 if(value.length < this.minLength){
4931 this.markInvalid(String.format(this.minLengthText, this.minLength));
4934 if(value.length > this.maxLength){
4935 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
4939 var vt = Roo.form.VTypes;
4940 if(!vt[this.vtype](value, this)){
4941 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
4945 if(typeof this.validator == "function"){
4946 var msg = this.validator(value);
4948 this.markInvalid(msg);
4952 if(this.regex && !this.regex.test(value)){
4953 this.markInvalid(this.regexText);
4962 fireKey : function(e){
4963 //Roo.log('field ' + e.getKey());
4964 if(e.isNavKeyPress()){
4965 this.fireEvent("specialkey", this, e);
4968 focus : function (selectText){
4970 this.inputEl().focus();
4971 if(selectText === true){
4972 this.inputEl().dom.select();
4978 onFocus : function(){
4979 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
4980 // this.el.addClass(this.focusClass);
4983 this.hasFocus = true;
4984 this.startValue = this.getValue();
4985 this.fireEvent("focus", this);
4989 beforeBlur : Roo.emptyFn,
4993 onBlur : function(){
4995 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
4996 //this.el.removeClass(this.focusClass);
4998 this.hasFocus = false;
4999 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
5002 var v = this.getValue();
5003 if(String(v) !== String(this.startValue)){
5004 this.fireEvent('change', this, v, this.startValue);
5006 this.fireEvent("blur", this);
5010 * Resets the current field value to the originally loaded value and clears any validation messages
5013 this.setValue(this.originalValue);
5014 this.clearInvalid();
5017 * Returns the name of the field
5018 * @return {Mixed} name The name field
5020 getName: function(){
5024 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
5025 * @return {Mixed} value The field value
5027 getValue : function(){
5028 return this.inputEl().getValue();
5031 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
5032 * @return {Mixed} value The field value
5034 getRawValue : function(){
5035 var v = this.inputEl().getValue();
5041 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
5042 * @param {Mixed} value The value to set
5044 setRawValue : function(v){
5045 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
5048 selectText : function(start, end){
5049 var v = this.getRawValue();
5051 start = start === undefined ? 0 : start;
5052 end = end === undefined ? v.length : end;
5053 var d = this.inputEl().dom;
5054 if(d.setSelectionRange){
5055 d.setSelectionRange(start, end);
5056 }else if(d.createTextRange){
5057 var range = d.createTextRange();
5058 range.moveStart("character", start);
5059 range.moveEnd("character", v.length-end);
5066 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
5067 * @param {Mixed} value The value to set
5069 setValue : function(v){
5072 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
5078 processValue : function(value){
5079 if(this.stripCharsRe){
5080 var newValue = value.replace(this.stripCharsRe, '');
5081 if(newValue !== value){
5082 this.setRawValue(newValue);
5089 preFocus : function(){
5091 if(this.selectOnFocus){
5092 this.inputEl().dom.select();
5095 filterKeys : function(e){
5097 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
5100 var c = e.getCharCode(), cc = String.fromCharCode(c);
5101 if(Roo.isIE && (e.isSpecialKey() || !cc)){
5104 if(!this.maskRe.test(cc)){
5109 * Clear any invalid styles/messages for this field
5111 clearInvalid : function(){
5113 if(!this.el || this.preventMark){ // not rendered
5116 this.el.removeClass(this.invalidClass);
5118 switch(this.msgTarget){
5120 this.el.dom.qtip = '';
5123 this.el.dom.title = '';
5127 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
5132 this.errorIcon.dom.qtip = '';
5133 this.errorIcon.hide();
5134 this.un('resize', this.alignErrorIcon, this);
5138 var t = Roo.getDom(this.msgTarget);
5140 t.style.display = 'none';
5144 this.fireEvent('valid', this);
5147 * Mark this field as invalid
5148 * @param {String} msg The validation message
5150 markInvalid : function(msg){
5151 if(!this.el || this.preventMark){ // not rendered
5154 this.el.addClass(this.invalidClass);
5156 msg = msg || this.invalidText;
5157 switch(this.msgTarget){
5159 this.el.dom.qtip = msg;
5160 this.el.dom.qclass = 'x-form-invalid-tip';
5161 if(Roo.QuickTips){ // fix for floating editors interacting with DND
5162 Roo.QuickTips.enable();
5166 this.el.dom.title = msg;
5170 var elp = this.el.findParent('.x-form-element', 5, true);
5171 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
5172 this.errorEl.setWidth(elp.getWidth(true)-20);
5174 this.errorEl.update(msg);
5175 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
5178 if(!this.errorIcon){
5179 var elp = this.el.findParent('.x-form-element', 5, true);
5180 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
5182 this.alignErrorIcon();
5183 this.errorIcon.dom.qtip = msg;
5184 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
5185 this.errorIcon.show();
5186 this.on('resize', this.alignErrorIcon, this);
5189 var t = Roo.getDom(this.msgTarget);
5191 t.style.display = this.msgDisplay;
5195 this.fireEvent('invalid', this, msg);
5198 SafariOnKeyDown : function(event)
5200 // this is a workaround for a password hang bug on chrome/ webkit.
5202 var isSelectAll = false;
5204 if(this.inputEl().dom.selectionEnd > 0){
5205 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
5207 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
5208 event.preventDefault();
5213 if(isSelectAll){ // backspace and delete key
5215 event.preventDefault();
5216 // this is very hacky as keydown always get's upper case.
5218 var cc = String.fromCharCode(event.getCharCode());
5219 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
5223 adjustWidth : function(tag, w){
5224 tag = tag.toLowerCase();
5225 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
5226 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
5230 if(tag == 'textarea'){
5233 }else if(Roo.isOpera){
5237 if(tag == 'textarea'){
5256 * @class Roo.bootstrap.TextArea
5257 * @extends Roo.bootstrap.Input
5258 * Bootstrap TextArea class
5259 * @cfg {Number} cols Specifies the visible width of a text area
5260 * @cfg {Number} rows Specifies the visible number of lines in a text area
5261 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
5262 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
5263 * @cfg {string} html text
5266 * Create a new TextArea
5267 * @param {Object} config The config object
5270 Roo.bootstrap.TextArea = function(config){
5271 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
5275 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
5285 getAutoCreate : function(){
5287 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
5298 value : this.value || '',
5299 html: this.html || '',
5300 cls : 'form-control',
5301 placeholder : this.placeholder || ''
5305 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
5306 input.maxLength = this.maxLength;
5310 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
5314 input.cols = this.cols;
5317 if (this.readOnly) {
5318 input.readonly = true;
5322 input.name = this.name;
5326 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
5330 ['xs','sm','md','lg'].map(function(size){
5331 if (settings[size]) {
5332 cfg.cls += ' col-' + size + '-' + settings[size];
5336 var inputblock = input;
5338 if (this.before || this.after) {
5341 cls : 'input-group',
5345 inputblock.cn.push({
5347 cls : 'input-group-addon',
5351 inputblock.cn.push(input);
5353 inputblock.cn.push({
5355 cls : 'input-group-addon',
5362 if (align ==='left' && this.fieldLabel.length) {
5363 Roo.log("left and has label");
5369 cls : 'control-label col-sm-' + this.labelWidth,
5370 html : this.fieldLabel
5374 cls : "col-sm-" + (12 - this.labelWidth),
5381 } else if ( this.fieldLabel.length) {
5387 //cls : 'input-group-addon',
5388 html : this.fieldLabel
5398 Roo.log(" no label && no align");
5408 if (this.disabled) {
5409 input.disabled=true;
5416 * return the real textarea element.
5418 inputEl: function ()
5420 return this.el.select('textarea.form-control',true).first();
5428 * trigger field - base class for combo..
5433 * @class Roo.bootstrap.TriggerField
5434 * @extends Roo.bootstrap.Input
5435 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
5436 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
5437 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
5438 * for which you can provide a custom implementation. For example:
5440 var trigger = new Roo.bootstrap.TriggerField();
5441 trigger.onTriggerClick = myTriggerFn;
5442 trigger.applyTo('my-field');
5445 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
5446 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
5447 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
5448 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
5450 * Create a new TriggerField.
5451 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
5452 * to the base TextField)
5454 Roo.bootstrap.TriggerField = function(config){
5455 this.mimicing = false;
5456 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
5459 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
5461 * @cfg {String} triggerClass A CSS class to apply to the trigger
5464 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
5468 /** @cfg {Boolean} grow @hide */
5469 /** @cfg {Number} growMin @hide */
5470 /** @cfg {Number} growMax @hide */
5476 autoSize: Roo.emptyFn,
5483 actionMode : 'wrap',
5487 getAutoCreate : function(){
5489 var parent = this.parent();
5491 var align = this.parentLabelAlign();
5496 cls: 'form-group' //input-group
5503 type : this.inputType,
5504 cls : 'form-control',
5505 autocomplete: 'off',
5506 placeholder : this.placeholder || ''
5510 input.name = this.name;
5513 input.cls += ' input-' + this.size;
5516 if (this.disabled) {
5517 input.disabled=true;
5520 var inputblock = input;
5522 if (this.before || this.after) {
5525 cls : 'input-group',
5529 inputblock.cn.push({
5531 cls : 'input-group-addon',
5535 inputblock.cn.push(input);
5537 inputblock.cn.push({
5539 cls : 'input-group-addon',
5552 cls: 'form-hidden-field'
5560 Roo.log('multiple');
5568 cls: 'form-hidden-field'
5572 cls: 'select2-choices',
5576 cls: 'select2-search-field',
5589 cls: 'select2-container input-group',
5594 cls: 'typeahead typeahead-long dropdown-menu',
5595 style: 'display:none'
5603 cls : 'input-group-addon btn dropdown-toggle',
5611 cls: 'combobox-clear',
5625 combobox.cls += ' select2-container-multi';
5628 if (align ==='left' && this.fieldLabel.length) {
5630 Roo.log("left and has label");
5636 cls : 'control-label col-sm-' + this.labelWidth,
5637 html : this.fieldLabel
5641 cls : "col-sm-" + (12 - this.labelWidth),
5648 } else if ( this.fieldLabel.length) {
5654 //cls : 'input-group-addon',
5655 html : this.fieldLabel
5665 Roo.log(" no label && no align");
5672 ['xs','sm','md','lg'].map(function(size){
5673 if (settings[size]) {
5674 cfg.cls += ' col-' + size + '-' + settings[size];
5685 onResize : function(w, h){
5686 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
5687 // if(typeof w == 'number'){
5688 // var x = w - this.trigger.getWidth();
5689 // this.inputEl().setWidth(this.adjustWidth('input', x));
5690 // this.trigger.setStyle('left', x+'px');
5695 adjustSize : Roo.BoxComponent.prototype.adjustSize,
5698 getResizeEl : function(){
5699 return this.inputEl();
5703 getPositionEl : function(){
5704 return this.inputEl();
5708 alignErrorIcon : function(){
5709 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
5713 initEvents : function(){
5715 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
5716 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
5718 this.trigger = this.el.select('span.dropdown-toggle',true).first();
5719 if(this.hideTrigger){
5720 this.trigger.setDisplayed(false);
5722 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
5726 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
5729 //this.trigger.addClassOnOver('x-form-trigger-over');
5730 //this.trigger.addClassOnClick('x-form-trigger-click');
5733 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
5738 initTrigger : function(){
5743 onDestroy : function(){
5745 this.trigger.removeAllListeners();
5746 // this.trigger.remove();
5749 // this.wrap.remove();
5751 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
5755 onFocus : function(){
5756 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
5759 this.wrap.addClass('x-trigger-wrap-focus');
5760 this.mimicing = true;
5761 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
5762 if(this.monitorTab){
5763 this.el.on("keydown", this.checkTab, this);
5770 checkTab : function(e){
5771 if(e.getKey() == e.TAB){
5777 onBlur : function(){
5782 mimicBlur : function(e, t){
5784 if(!this.wrap.contains(t) && this.validateBlur()){
5791 triggerBlur : function(){
5792 this.mimicing = false;
5793 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
5794 if(this.monitorTab){
5795 this.el.un("keydown", this.checkTab, this);
5797 //this.wrap.removeClass('x-trigger-wrap-focus');
5798 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
5802 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
5803 validateBlur : function(e, t){
5808 onDisable : function(){
5809 Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
5811 // this.wrap.addClass('x-item-disabled');
5816 onEnable : function(){
5817 Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
5819 // this.el.removeClass('x-item-disabled');
5824 onShow : function(){
5825 var ae = this.getActionEl();
5828 ae.dom.style.display = '';
5829 ae.dom.style.visibility = 'visible';
5835 onHide : function(){
5836 var ae = this.getActionEl();
5837 ae.dom.style.display = 'none';
5841 * The function that should handle the trigger's click event. This method does nothing by default until overridden
5842 * by an implementing function.
5844 * @param {EventObject} e
5846 onTriggerClick : Roo.emptyFn
5850 * Ext JS Library 1.1.1
5851 * Copyright(c) 2006-2007, Ext JS, LLC.
5853 * Originally Released Under LGPL - original licence link has changed is not relivant.
5856 * <script type="text/javascript">
5861 * @class Roo.data.SortTypes
5863 * Defines the default sorting (casting?) comparison functions used when sorting data.
5865 Roo.data.SortTypes = {
5867 * Default sort that does nothing
5868 * @param {Mixed} s The value being converted
5869 * @return {Mixed} The comparison value
5876 * The regular expression used to strip tags
5880 stripTagsRE : /<\/?[^>]+>/gi,
5883 * Strips all HTML tags to sort on text only
5884 * @param {Mixed} s The value being converted
5885 * @return {String} The comparison value
5887 asText : function(s){
5888 return String(s).replace(this.stripTagsRE, "");
5892 * Strips all HTML tags to sort on text only - Case insensitive
5893 * @param {Mixed} s The value being converted
5894 * @return {String} The comparison value
5896 asUCText : function(s){
5897 return String(s).toUpperCase().replace(this.stripTagsRE, "");
5901 * Case insensitive string
5902 * @param {Mixed} s The value being converted
5903 * @return {String} The comparison value
5905 asUCString : function(s) {
5906 return String(s).toUpperCase();
5911 * @param {Mixed} s The value being converted
5912 * @return {Number} The comparison value
5914 asDate : function(s) {
5918 if(s instanceof Date){
5921 return Date.parse(String(s));
5926 * @param {Mixed} s The value being converted
5927 * @return {Float} The comparison value
5929 asFloat : function(s) {
5930 var val = parseFloat(String(s).replace(/,/g, ""));
5931 if(isNaN(val)) val = 0;
5937 * @param {Mixed} s The value being converted
5938 * @return {Number} The comparison value
5940 asInt : function(s) {
5941 var val = parseInt(String(s).replace(/,/g, ""));
5942 if(isNaN(val)) val = 0;
5947 * Ext JS Library 1.1.1
5948 * Copyright(c) 2006-2007, Ext JS, LLC.
5950 * Originally Released Under LGPL - original licence link has changed is not relivant.
5953 * <script type="text/javascript">
5957 * @class Roo.data.Record
5958 * Instances of this class encapsulate both record <em>definition</em> information, and record
5959 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
5960 * to access Records cached in an {@link Roo.data.Store} object.<br>
5962 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
5963 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
5966 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
5968 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
5969 * {@link #create}. The parameters are the same.
5970 * @param {Array} data An associative Array of data values keyed by the field name.
5971 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
5972 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
5973 * not specified an integer id is generated.
5975 Roo.data.Record = function(data, id){
5976 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
5981 * Generate a constructor for a specific record layout.
5982 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
5983 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
5984 * Each field definition object may contain the following properties: <ul>
5985 * <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,
5986 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
5987 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
5988 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
5989 * is being used, then this is a string containing the javascript expression to reference the data relative to
5990 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
5991 * to the data item relative to the record element. If the mapping expression is the same as the field name,
5992 * this may be omitted.</p></li>
5993 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
5994 * <ul><li>auto (Default, implies no conversion)</li>
5999 * <li>date</li></ul></p></li>
6000 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
6001 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
6002 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
6003 * by the Reader into an object that will be stored in the Record. It is passed the
6004 * following parameters:<ul>
6005 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
6007 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
6009 * <br>usage:<br><pre><code>
6010 var TopicRecord = Roo.data.Record.create(
6011 {name: 'title', mapping: 'topic_title'},
6012 {name: 'author', mapping: 'username'},
6013 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
6014 {name: 'lastPost', mapping: 'post_time', type: 'date'},
6015 {name: 'lastPoster', mapping: 'user2'},
6016 {name: 'excerpt', mapping: 'post_text'}
6019 var myNewRecord = new TopicRecord({
6020 title: 'Do my job please',
6023 lastPost: new Date(),
6024 lastPoster: 'Animal',
6025 excerpt: 'No way dude!'
6027 myStore.add(myNewRecord);
6032 Roo.data.Record.create = function(o){
6034 f.superclass.constructor.apply(this, arguments);
6036 Roo.extend(f, Roo.data.Record);
6037 var p = f.prototype;
6038 p.fields = new Roo.util.MixedCollection(false, function(field){
6041 for(var i = 0, len = o.length; i < len; i++){
6042 p.fields.add(new Roo.data.Field(o[i]));
6044 f.getField = function(name){
6045 return p.fields.get(name);
6050 Roo.data.Record.AUTO_ID = 1000;
6051 Roo.data.Record.EDIT = 'edit';
6052 Roo.data.Record.REJECT = 'reject';
6053 Roo.data.Record.COMMIT = 'commit';
6055 Roo.data.Record.prototype = {
6057 * Readonly flag - true if this record has been modified.
6066 join : function(store){
6071 * Set the named field to the specified value.
6072 * @param {String} name The name of the field to set.
6073 * @param {Object} value The value to set the field to.
6075 set : function(name, value){
6076 if(this.data[name] == value){
6083 if(typeof this.modified[name] == 'undefined'){
6084 this.modified[name] = this.data[name];
6086 this.data[name] = value;
6087 if(!this.editing && this.store){
6088 this.store.afterEdit(this);
6093 * Get the value of the named field.
6094 * @param {String} name The name of the field to get the value of.
6095 * @return {Object} The value of the field.
6097 get : function(name){
6098 return this.data[name];
6102 beginEdit : function(){
6103 this.editing = true;
6108 cancelEdit : function(){
6109 this.editing = false;
6110 delete this.modified;
6114 endEdit : function(){
6115 this.editing = false;
6116 if(this.dirty && this.store){
6117 this.store.afterEdit(this);
6122 * Usually called by the {@link Roo.data.Store} which owns the Record.
6123 * Rejects all changes made to the Record since either creation, or the last commit operation.
6124 * Modified fields are reverted to their original values.
6126 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
6127 * of reject operations.
6129 reject : function(){
6130 var m = this.modified;
6132 if(typeof m[n] != "function"){
6133 this.data[n] = m[n];
6137 delete this.modified;
6138 this.editing = false;
6140 this.store.afterReject(this);
6145 * Usually called by the {@link Roo.data.Store} which owns the Record.
6146 * Commits all changes made to the Record since either creation, or the last commit operation.
6148 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
6149 * of commit operations.
6151 commit : function(){
6153 delete this.modified;
6154 this.editing = false;
6156 this.store.afterCommit(this);
6161 hasError : function(){
6162 return this.error != null;
6166 clearError : function(){
6171 * Creates a copy of this record.
6172 * @param {String} id (optional) A new record id if you don't want to use this record's id
6175 copy : function(newId) {
6176 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
6180 * Ext JS Library 1.1.1
6181 * Copyright(c) 2006-2007, Ext JS, LLC.
6183 * Originally Released Under LGPL - original licence link has changed is not relivant.
6186 * <script type="text/javascript">
6192 * @class Roo.data.Store
6193 * @extends Roo.util.Observable
6194 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
6195 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
6197 * 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
6198 * has no knowledge of the format of the data returned by the Proxy.<br>
6200 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
6201 * instances from the data object. These records are cached and made available through accessor functions.
6203 * Creates a new Store.
6204 * @param {Object} config A config object containing the objects needed for the Store to access data,
6205 * and read the data into Records.
6207 Roo.data.Store = function(config){
6208 this.data = new Roo.util.MixedCollection(false);
6209 this.data.getKey = function(o){
6212 this.baseParams = {};
6219 "multisort" : "_multisort"
6222 if(config && config.data){
6223 this.inlineData = config.data;
6227 Roo.apply(this, config);
6229 if(this.reader){ // reader passed
6230 this.reader = Roo.factory(this.reader, Roo.data);
6231 this.reader.xmodule = this.xmodule || false;
6232 if(!this.recordType){
6233 this.recordType = this.reader.recordType;
6235 if(this.reader.onMetaChange){
6236 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
6240 if(this.recordType){
6241 this.fields = this.recordType.prototype.fields;
6247 * @event datachanged
6248 * Fires when the data cache has changed, and a widget which is using this Store
6249 * as a Record cache should refresh its view.
6250 * @param {Store} this
6255 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
6256 * @param {Store} this
6257 * @param {Object} meta The JSON metadata
6262 * Fires when Records have been added to the Store
6263 * @param {Store} this
6264 * @param {Roo.data.Record[]} records The array of Records added
6265 * @param {Number} index The index at which the record(s) were added
6270 * Fires when a Record has been removed from the Store
6271 * @param {Store} this
6272 * @param {Roo.data.Record} record The Record that was removed
6273 * @param {Number} index The index at which the record was removed
6278 * Fires when a Record has been updated
6279 * @param {Store} this
6280 * @param {Roo.data.Record} record The Record that was updated
6281 * @param {String} operation The update operation being performed. Value may be one of:
6283 Roo.data.Record.EDIT
6284 Roo.data.Record.REJECT
6285 Roo.data.Record.COMMIT
6291 * Fires when the data cache has been cleared.
6292 * @param {Store} this
6297 * Fires before a request is made for a new data object. If the beforeload handler returns false
6298 * the load action will be canceled.
6299 * @param {Store} this
6300 * @param {Object} options The loading options that were specified (see {@link #load} for details)
6304 * @event beforeloadadd
6305 * Fires after a new set of Records has been loaded.
6306 * @param {Store} this
6307 * @param {Roo.data.Record[]} records The Records that were loaded
6308 * @param {Object} options The loading options that were specified (see {@link #load} for details)
6310 beforeloadadd : true,
6313 * Fires after a new set of Records has been loaded, before they are added to the store.
6314 * @param {Store} this
6315 * @param {Roo.data.Record[]} records The Records that were loaded
6316 * @param {Object} options The loading options that were specified (see {@link #load} for details)
6317 * @params {Object} return from reader
6321 * @event loadexception
6322 * Fires if an exception occurs in the Proxy during loading.
6323 * Called with the signature of the Proxy's "loadexception" event.
6324 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
6327 * @param {Object} return from JsonData.reader() - success, totalRecords, records
6328 * @param {Object} load options
6329 * @param {Object} jsonData from your request (normally this contains the Exception)
6331 loadexception : true
6335 this.proxy = Roo.factory(this.proxy, Roo.data);
6336 this.proxy.xmodule = this.xmodule || false;
6337 this.relayEvents(this.proxy, ["loadexception"]);
6339 this.sortToggle = {};
6340 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
6342 Roo.data.Store.superclass.constructor.call(this);
6344 if(this.inlineData){
6345 this.loadData(this.inlineData);
6346 delete this.inlineData;
6350 Roo.extend(Roo.data.Store, Roo.util.Observable, {
6352 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
6353 * without a remote query - used by combo/forms at present.
6357 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
6360 * @cfg {Array} data Inline data to be loaded when the store is initialized.
6363 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
6364 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
6367 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
6368 * on any HTTP request
6371 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
6374 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
6378 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
6379 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
6384 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
6385 * loaded or when a record is removed. (defaults to false).
6387 pruneModifiedRecords : false,
6393 * Add Records to the Store and fires the add event.
6394 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
6396 add : function(records){
6397 records = [].concat(records);
6398 for(var i = 0, len = records.length; i < len; i++){
6399 records[i].join(this);
6401 var index = this.data.length;
6402 this.data.addAll(records);
6403 this.fireEvent("add", this, records, index);
6407 * Remove a Record from the Store and fires the remove event.
6408 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
6410 remove : function(record){
6411 var index = this.data.indexOf(record);
6412 this.data.removeAt(index);
6413 if(this.pruneModifiedRecords){
6414 this.modified.remove(record);
6416 this.fireEvent("remove", this, record, index);
6420 * Remove all Records from the Store and fires the clear event.
6422 removeAll : function(){
6424 if(this.pruneModifiedRecords){
6427 this.fireEvent("clear", this);
6431 * Inserts Records to the Store at the given index and fires the add event.
6432 * @param {Number} index The start index at which to insert the passed Records.
6433 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
6435 insert : function(index, records){
6436 records = [].concat(records);
6437 for(var i = 0, len = records.length; i < len; i++){
6438 this.data.insert(index, records[i]);
6439 records[i].join(this);
6441 this.fireEvent("add", this, records, index);
6445 * Get the index within the cache of the passed Record.
6446 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
6447 * @return {Number} The index of the passed Record. Returns -1 if not found.
6449 indexOf : function(record){
6450 return this.data.indexOf(record);
6454 * Get the index within the cache of the Record with the passed id.
6455 * @param {String} id The id of the Record to find.
6456 * @return {Number} The index of the Record. Returns -1 if not found.
6458 indexOfId : function(id){
6459 return this.data.indexOfKey(id);
6463 * Get the Record with the specified id.
6464 * @param {String} id The id of the Record to find.
6465 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
6467 getById : function(id){
6468 return this.data.key(id);
6472 * Get the Record at the specified index.
6473 * @param {Number} index The index of the Record to find.
6474 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
6476 getAt : function(index){
6477 return this.data.itemAt(index);
6481 * Returns a range of Records between specified indices.
6482 * @param {Number} startIndex (optional) The starting index (defaults to 0)
6483 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
6484 * @return {Roo.data.Record[]} An array of Records
6486 getRange : function(start, end){
6487 return this.data.getRange(start, end);
6491 storeOptions : function(o){
6492 o = Roo.apply({}, o);
6495 this.lastOptions = o;
6499 * Loads the Record cache from the configured Proxy using the configured Reader.
6501 * If using remote paging, then the first load call must specify the <em>start</em>
6502 * and <em>limit</em> properties in the options.params property to establish the initial
6503 * position within the dataset, and the number of Records to cache on each read from the Proxy.
6505 * <strong>It is important to note that for remote data sources, loading is asynchronous,
6506 * and this call will return before the new data has been loaded. Perform any post-processing
6507 * in a callback function, or in a "load" event handler.</strong>
6509 * @param {Object} options An object containing properties which control loading options:<ul>
6510 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
6511 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
6512 * passed the following arguments:<ul>
6513 * <li>r : Roo.data.Record[]</li>
6514 * <li>options: Options object from the load call</li>
6515 * <li>success: Boolean success indicator</li></ul></li>
6516 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
6517 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
6520 load : function(options){
6521 options = options || {};
6522 if(this.fireEvent("beforeload", this, options) !== false){
6523 this.storeOptions(options);
6524 var p = Roo.apply(options.params || {}, this.baseParams);
6525 // if meta was not loaded from remote source.. try requesting it.
6526 if (!this.reader.metaFromRemote) {
6529 if(this.sortInfo && this.remoteSort){
6530 var pn = this.paramNames;
6531 p[pn["sort"]] = this.sortInfo.field;
6532 p[pn["dir"]] = this.sortInfo.direction;
6534 if (this.multiSort) {
6535 var pn = this.paramNames;
6536 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
6539 this.proxy.load(p, this.reader, this.loadRecords, this, options);
6544 * Reloads the Record cache from the configured Proxy using the configured Reader and
6545 * the options from the last load operation performed.
6546 * @param {Object} options (optional) An object containing properties which may override the options
6547 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
6548 * the most recently used options are reused).
6550 reload : function(options){
6551 this.load(Roo.applyIf(options||{}, this.lastOptions));
6555 // Called as a callback by the Reader during a load operation.
6556 loadRecords : function(o, options, success){
6557 if(!o || success === false){
6558 if(success !== false){
6559 this.fireEvent("load", this, [], options, o);
6561 if(options.callback){
6562 options.callback.call(options.scope || this, [], options, false);
6566 // if data returned failure - throw an exception.
6567 if (o.success === false) {
6568 // show a message if no listener is registered.
6569 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
6570 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
6572 // loadmask wil be hooked into this..
6573 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
6576 var r = o.records, t = o.totalRecords || r.length;
6578 this.fireEvent("beforeloadadd", this, r, options, o);
6580 if(!options || options.add !== true){
6581 if(this.pruneModifiedRecords){
6584 for(var i = 0, len = r.length; i < len; i++){
6588 this.data = this.snapshot;
6589 delete this.snapshot;
6592 this.data.addAll(r);
6593 this.totalLength = t;
6595 this.fireEvent("datachanged", this);
6597 this.totalLength = Math.max(t, this.data.length+r.length);
6600 this.fireEvent("load", this, r, options, o);
6601 if(options.callback){
6602 options.callback.call(options.scope || this, r, options, true);
6608 * Loads data from a passed data block. A Reader which understands the format of the data
6609 * must have been configured in the constructor.
6610 * @param {Object} data The data block from which to read the Records. The format of the data expected
6611 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
6612 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
6614 loadData : function(o, append){
6615 var r = this.reader.readRecords(o);
6616 this.loadRecords(r, {add: append}, true);
6620 * Gets the number of cached records.
6622 * <em>If using paging, this may not be the total size of the dataset. If the data object
6623 * used by the Reader contains the dataset size, then the getTotalCount() function returns
6624 * the data set size</em>
6626 getCount : function(){
6627 return this.data.length || 0;
6631 * Gets the total number of records in the dataset as returned by the server.
6633 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
6634 * the dataset size</em>
6636 getTotalCount : function(){
6637 return this.totalLength || 0;
6641 * Returns the sort state of the Store as an object with two properties:
6643 field {String} The name of the field by which the Records are sorted
6644 direction {String} The sort order, "ASC" or "DESC"
6647 getSortState : function(){
6648 return this.sortInfo;
6652 applySort : function(){
6653 if(this.sortInfo && !this.remoteSort){
6654 var s = this.sortInfo, f = s.field;
6655 var st = this.fields.get(f).sortType;
6656 var fn = function(r1, r2){
6657 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
6658 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
6660 this.data.sort(s.direction, fn);
6661 if(this.snapshot && this.snapshot != this.data){
6662 this.snapshot.sort(s.direction, fn);
6668 * Sets the default sort column and order to be used by the next load operation.
6669 * @param {String} fieldName The name of the field to sort by.
6670 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
6672 setDefaultSort : function(field, dir){
6673 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
6678 * If remote sorting is used, the sort is performed on the server, and the cache is
6679 * reloaded. If local sorting is used, the cache is sorted internally.
6680 * @param {String} fieldName The name of the field to sort by.
6681 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
6683 sort : function(fieldName, dir){
6684 var f = this.fields.get(fieldName);
6686 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
6688 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
6689 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
6694 this.sortToggle[f.name] = dir;
6695 this.sortInfo = {field: f.name, direction: dir};
6696 if(!this.remoteSort){
6698 this.fireEvent("datachanged", this);
6700 this.load(this.lastOptions);
6705 * Calls the specified function for each of the Records in the cache.
6706 * @param {Function} fn The function to call. The Record is passed as the first parameter.
6707 * Returning <em>false</em> aborts and exits the iteration.
6708 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
6710 each : function(fn, scope){
6711 this.data.each(fn, scope);
6715 * Gets all records modified since the last commit. Modified records are persisted across load operations
6716 * (e.g., during paging).
6717 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
6719 getModifiedRecords : function(){
6720 return this.modified;
6724 createFilterFn : function(property, value, anyMatch){
6725 if(!value.exec){ // not a regex
6726 value = String(value);
6727 if(value.length == 0){
6730 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
6733 return value.test(r.data[property]);
6738 * Sums the value of <i>property</i> for each record between start and end and returns the result.
6739 * @param {String} property A field on your records
6740 * @param {Number} start The record index to start at (defaults to 0)
6741 * @param {Number} end The last record index to include (defaults to length - 1)
6742 * @return {Number} The sum
6744 sum : function(property, start, end){
6745 var rs = this.data.items, v = 0;
6747 end = (end || end === 0) ? end : rs.length-1;
6749 for(var i = start; i <= end; i++){
6750 v += (rs[i].data[property] || 0);
6756 * Filter the records by a specified property.
6757 * @param {String} field A field on your records
6758 * @param {String/RegExp} value Either a string that the field
6759 * should start with or a RegExp to test against the field
6760 * @param {Boolean} anyMatch True to match any part not just the beginning
6762 filter : function(property, value, anyMatch){
6763 var fn = this.createFilterFn(property, value, anyMatch);
6764 return fn ? this.filterBy(fn) : this.clearFilter();
6768 * Filter by a function. The specified function will be called with each
6769 * record in this data source. If the function returns true the record is included,
6770 * otherwise it is filtered.
6771 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
6772 * @param {Object} scope (optional) The scope of the function (defaults to this)
6774 filterBy : function(fn, scope){
6775 this.snapshot = this.snapshot || this.data;
6776 this.data = this.queryBy(fn, scope||this);
6777 this.fireEvent("datachanged", this);
6781 * Query the records by a specified property.
6782 * @param {String} field A field on your records
6783 * @param {String/RegExp} value Either a string that the field
6784 * should start with or a RegExp to test against the field
6785 * @param {Boolean} anyMatch True to match any part not just the beginning
6786 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
6788 query : function(property, value, anyMatch){
6789 var fn = this.createFilterFn(property, value, anyMatch);
6790 return fn ? this.queryBy(fn) : this.data.clone();
6794 * Query by a function. The specified function will be called with each
6795 * record in this data source. If the function returns true the record is included
6797 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
6798 * @param {Object} scope (optional) The scope of the function (defaults to this)
6799 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
6801 queryBy : function(fn, scope){
6802 var data = this.snapshot || this.data;
6803 return data.filterBy(fn, scope||this);
6807 * Collects unique values for a particular dataIndex from this store.
6808 * @param {String} dataIndex The property to collect
6809 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
6810 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
6811 * @return {Array} An array of the unique values
6813 collect : function(dataIndex, allowNull, bypassFilter){
6814 var d = (bypassFilter === true && this.snapshot) ?
6815 this.snapshot.items : this.data.items;
6816 var v, sv, r = [], l = {};
6817 for(var i = 0, len = d.length; i < len; i++){
6818 v = d[i].data[dataIndex];
6820 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
6829 * Revert to a view of the Record cache with no filtering applied.
6830 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
6832 clearFilter : function(suppressEvent){
6833 if(this.snapshot && this.snapshot != this.data){
6834 this.data = this.snapshot;
6835 delete this.snapshot;
6836 if(suppressEvent !== true){
6837 this.fireEvent("datachanged", this);
6843 afterEdit : function(record){
6844 if(this.modified.indexOf(record) == -1){
6845 this.modified.push(record);
6847 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
6851 afterReject : function(record){
6852 this.modified.remove(record);
6853 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
6857 afterCommit : function(record){
6858 this.modified.remove(record);
6859 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
6863 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
6864 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
6866 commitChanges : function(){
6867 var m = this.modified.slice(0);
6869 for(var i = 0, len = m.length; i < len; i++){
6875 * Cancel outstanding changes on all changed records.
6877 rejectChanges : function(){
6878 var m = this.modified.slice(0);
6880 for(var i = 0, len = m.length; i < len; i++){
6885 onMetaChange : function(meta, rtype, o){
6886 this.recordType = rtype;
6887 this.fields = rtype.prototype.fields;
6888 delete this.snapshot;
6889 this.sortInfo = meta.sortInfo || this.sortInfo;
6891 this.fireEvent('metachange', this, this.reader.meta);
6894 moveIndex : function(data, type)
6896 var index = this.indexOf(data);
6898 var newIndex = index + type;
6902 this.insert(newIndex, data);
6907 * Ext JS Library 1.1.1
6908 * Copyright(c) 2006-2007, Ext JS, LLC.
6910 * Originally Released Under LGPL - original licence link has changed is not relivant.
6913 * <script type="text/javascript">
6917 * @class Roo.data.SimpleStore
6918 * @extends Roo.data.Store
6919 * Small helper class to make creating Stores from Array data easier.
6920 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
6921 * @cfg {Array} fields An array of field definition objects, or field name strings.
6922 * @cfg {Array} data The multi-dimensional array of data
6924 * @param {Object} config
6926 Roo.data.SimpleStore = function(config){
6927 Roo.data.SimpleStore.superclass.constructor.call(this, {
6929 reader: new Roo.data.ArrayReader({
6932 Roo.data.Record.create(config.fields)
6934 proxy : new Roo.data.MemoryProxy(config.data)
6938 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
6940 * Ext JS Library 1.1.1
6941 * Copyright(c) 2006-2007, Ext JS, LLC.
6943 * Originally Released Under LGPL - original licence link has changed is not relivant.
6946 * <script type="text/javascript">
6951 * @extends Roo.data.Store
6952 * @class Roo.data.JsonStore
6953 * Small helper class to make creating Stores for JSON data easier. <br/>
6955 var store = new Roo.data.JsonStore({
6956 url: 'get-images.php',
6958 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
6961 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
6962 * JsonReader and HttpProxy (unless inline data is provided).</b>
6963 * @cfg {Array} fields An array of field definition objects, or field name strings.
6965 * @param {Object} config
6967 Roo.data.JsonStore = function(c){
6968 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
6969 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
6970 reader: new Roo.data.JsonReader(c, c.fields)
6973 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
6975 * Ext JS Library 1.1.1
6976 * Copyright(c) 2006-2007, Ext JS, LLC.
6978 * Originally Released Under LGPL - original licence link has changed is not relivant.
6981 * <script type="text/javascript">
6985 Roo.data.Field = function(config){
6986 if(typeof config == "string"){
6987 config = {name: config};
6989 Roo.apply(this, config);
6995 var st = Roo.data.SortTypes;
6996 // named sortTypes are supported, here we look them up
6997 if(typeof this.sortType == "string"){
6998 this.sortType = st[this.sortType];
7001 // set default sortType for strings and dates
7005 this.sortType = st.asUCString;
7008 this.sortType = st.asDate;
7011 this.sortType = st.none;
7016 var stripRe = /[\$,%]/g;
7018 // prebuilt conversion function for this field, instead of
7019 // switching every time we're reading a value
7021 var cv, dateFormat = this.dateFormat;
7026 cv = function(v){ return v; };
7029 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
7033 return v !== undefined && v !== null && v !== '' ?
7034 parseInt(String(v).replace(stripRe, ""), 10) : '';
7039 return v !== undefined && v !== null && v !== '' ?
7040 parseFloat(String(v).replace(stripRe, ""), 10) : '';
7045 cv = function(v){ return v === true || v === "true" || v == 1; };
7052 if(v instanceof Date){
7056 if(dateFormat == "timestamp"){
7057 return new Date(v*1000);
7059 return Date.parseDate(v, dateFormat);
7061 var parsed = Date.parse(v);
7062 return parsed ? new Date(parsed) : null;
7071 Roo.data.Field.prototype = {
7079 * Ext JS Library 1.1.1
7080 * Copyright(c) 2006-2007, Ext JS, LLC.
7082 * Originally Released Under LGPL - original licence link has changed is not relivant.
7085 * <script type="text/javascript">
7088 // Base class for reading structured data from a data source. This class is intended to be
7089 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
7092 * @class Roo.data.DataReader
7093 * Base class for reading structured data from a data source. This class is intended to be
7094 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
7097 Roo.data.DataReader = function(meta, recordType){
7101 this.recordType = recordType instanceof Array ?
7102 Roo.data.Record.create(recordType) : recordType;
7105 Roo.data.DataReader.prototype = {
7107 * Create an empty record
7108 * @param {Object} data (optional) - overlay some values
7109 * @return {Roo.data.Record} record created.
7111 newRow : function(d) {
7113 this.recordType.prototype.fields.each(function(c) {
7115 case 'int' : da[c.name] = 0; break;
7116 case 'date' : da[c.name] = new Date(); break;
7117 case 'float' : da[c.name] = 0.0; break;
7118 case 'boolean' : da[c.name] = false; break;
7119 default : da[c.name] = ""; break;
7123 return new this.recordType(Roo.apply(da, d));
7128 * Ext JS Library 1.1.1
7129 * Copyright(c) 2006-2007, Ext JS, LLC.
7131 * Originally Released Under LGPL - original licence link has changed is not relivant.
7134 * <script type="text/javascript">
7138 * @class Roo.data.DataProxy
7139 * @extends Roo.data.Observable
7140 * This class is an abstract base class for implementations which provide retrieval of
7141 * unformatted data objects.<br>
7143 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
7144 * (of the appropriate type which knows how to parse the data object) to provide a block of
7145 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
7147 * Custom implementations must implement the load method as described in
7148 * {@link Roo.data.HttpProxy#load}.
7150 Roo.data.DataProxy = function(){
7154 * Fires before a network request is made to retrieve a data object.
7155 * @param {Object} This DataProxy object.
7156 * @param {Object} params The params parameter to the load function.
7161 * Fires before the load method's callback is called.
7162 * @param {Object} This DataProxy object.
7163 * @param {Object} o The data object.
7164 * @param {Object} arg The callback argument object passed to the load function.
7168 * @event loadexception
7169 * Fires if an Exception occurs during data retrieval.
7170 * @param {Object} This DataProxy object.
7171 * @param {Object} o The data object.
7172 * @param {Object} arg The callback argument object passed to the load function.
7173 * @param {Object} e The Exception.
7175 loadexception : true
7177 Roo.data.DataProxy.superclass.constructor.call(this);
7180 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
7183 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
7187 * Ext JS Library 1.1.1
7188 * Copyright(c) 2006-2007, Ext JS, LLC.
7190 * Originally Released Under LGPL - original licence link has changed is not relivant.
7193 * <script type="text/javascript">
7196 * @class Roo.data.MemoryProxy
7197 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
7198 * to the Reader when its load method is called.
7200 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
7202 Roo.data.MemoryProxy = function(data){
7206 Roo.data.MemoryProxy.superclass.constructor.call(this);
7210 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
7212 * Load data from the requested source (in this case an in-memory
7213 * data object passed to the constructor), read the data object into
7214 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
7215 * process that block using the passed callback.
7216 * @param {Object} params This parameter is not used by the MemoryProxy class.
7217 * @param {Roo.data.DataReader} reader The Reader object which converts the data
7218 * object into a block of Roo.data.Records.
7219 * @param {Function} callback The function into which to pass the block of Roo.data.records.
7220 * The function must be passed <ul>
7221 * <li>The Record block object</li>
7222 * <li>The "arg" argument from the load function</li>
7223 * <li>A boolean success indicator</li>
7225 * @param {Object} scope The scope in which to call the callback
7226 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
7228 load : function(params, reader, callback, scope, arg){
7229 params = params || {};
7232 result = reader.readRecords(this.data);
7234 this.fireEvent("loadexception", this, arg, null, e);
7235 callback.call(scope, null, arg, false);
7238 callback.call(scope, result, arg, true);
7242 update : function(params, records){
7247 * Ext JS Library 1.1.1
7248 * Copyright(c) 2006-2007, Ext JS, LLC.
7250 * Originally Released Under LGPL - original licence link has changed is not relivant.
7253 * <script type="text/javascript">
7256 * @class Roo.data.HttpProxy
7257 * @extends Roo.data.DataProxy
7258 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
7259 * configured to reference a certain URL.<br><br>
7261 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
7262 * from which the running page was served.<br><br>
7264 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
7266 * Be aware that to enable the browser to parse an XML document, the server must set
7267 * the Content-Type header in the HTTP response to "text/xml".
7269 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
7270 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
7271 * will be used to make the request.
7273 Roo.data.HttpProxy = function(conn){
7274 Roo.data.HttpProxy.superclass.constructor.call(this);
7275 // is conn a conn config or a real conn?
7277 this.useAjax = !conn || !conn.events;
7281 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
7282 // thse are take from connection...
7285 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
7288 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
7289 * extra parameters to each request made by this object. (defaults to undefined)
7292 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
7293 * to each request made by this object. (defaults to undefined)
7296 * @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)
7299 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
7302 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
7308 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
7312 * Return the {@link Roo.data.Connection} object being used by this Proxy.
7313 * @return {Connection} The Connection object. This object may be used to subscribe to events on
7314 * a finer-grained basis than the DataProxy events.
7316 getConnection : function(){
7317 return this.useAjax ? Roo.Ajax : this.conn;
7321 * Load data from the configured {@link Roo.data.Connection}, read the data object into
7322 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
7323 * process that block using the passed callback.
7324 * @param {Object} params An object containing properties which are to be used as HTTP parameters
7325 * for the request to the remote server.
7326 * @param {Roo.data.DataReader} reader The Reader object which converts the data
7327 * object into a block of Roo.data.Records.
7328 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
7329 * The function must be passed <ul>
7330 * <li>The Record block object</li>
7331 * <li>The "arg" argument from the load function</li>
7332 * <li>A boolean success indicator</li>
7334 * @param {Object} scope The scope in which to call the callback
7335 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
7337 load : function(params, reader, callback, scope, arg){
7338 if(this.fireEvent("beforeload", this, params) !== false){
7340 params : params || {},
7342 callback : callback,
7347 callback : this.loadResponse,
7351 Roo.applyIf(o, this.conn);
7352 if(this.activeRequest){
7353 Roo.Ajax.abort(this.activeRequest);
7355 this.activeRequest = Roo.Ajax.request(o);
7357 this.conn.request(o);
7360 callback.call(scope||this, null, arg, false);
7365 loadResponse : function(o, success, response){
7366 delete this.activeRequest;
7368 this.fireEvent("loadexception", this, o, response);
7369 o.request.callback.call(o.request.scope, null, o.request.arg, false);
7374 result = o.reader.read(response);
7376 this.fireEvent("loadexception", this, o, response, e);
7377 o.request.callback.call(o.request.scope, null, o.request.arg, false);
7381 this.fireEvent("load", this, o, o.request.arg);
7382 o.request.callback.call(o.request.scope, result, o.request.arg, true);
7386 update : function(dataSet){
7391 updateResponse : function(dataSet){
7396 * Ext JS Library 1.1.1
7397 * Copyright(c) 2006-2007, Ext JS, LLC.
7399 * Originally Released Under LGPL - original licence link has changed is not relivant.
7402 * <script type="text/javascript">
7406 * @class Roo.data.ScriptTagProxy
7407 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
7408 * other than the originating domain of the running page.<br><br>
7410 * <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
7411 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
7413 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
7414 * source code that is used as the source inside a <script> tag.<br><br>
7416 * In order for the browser to process the returned data, the server must wrap the data object
7417 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
7418 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
7419 * depending on whether the callback name was passed:
7422 boolean scriptTag = false;
7423 String cb = request.getParameter("callback");
7426 response.setContentType("text/javascript");
7428 response.setContentType("application/x-json");
7430 Writer out = response.getWriter();
7432 out.write(cb + "(");
7434 out.print(dataBlock.toJsonString());
7441 * @param {Object} config A configuration object.
7443 Roo.data.ScriptTagProxy = function(config){
7444 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
7445 Roo.apply(this, config);
7446 this.head = document.getElementsByTagName("head")[0];
7449 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
7451 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
7453 * @cfg {String} url The URL from which to request the data object.
7456 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
7460 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
7461 * the server the name of the callback function set up by the load call to process the returned data object.
7462 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
7463 * javascript output which calls this named function passing the data object as its only parameter.
7465 callbackParam : "callback",
7467 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
7468 * name to the request.
7473 * Load data from the configured URL, read the data object into
7474 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
7475 * process that block using the passed callback.
7476 * @param {Object} params An object containing properties which are to be used as HTTP parameters
7477 * for the request to the remote server.
7478 * @param {Roo.data.DataReader} reader The Reader object which converts the data
7479 * object into a block of Roo.data.Records.
7480 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
7481 * The function must be passed <ul>
7482 * <li>The Record block object</li>
7483 * <li>The "arg" argument from the load function</li>
7484 * <li>A boolean success indicator</li>
7486 * @param {Object} scope The scope in which to call the callback
7487 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
7489 load : function(params, reader, callback, scope, arg){
7490 if(this.fireEvent("beforeload", this, params) !== false){
7492 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
7495 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
7497 url += "&_dc=" + (new Date().getTime());
7499 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
7502 cb : "stcCallback"+transId,
7503 scriptId : "stcScript"+transId,
7507 callback : callback,
7513 window[trans.cb] = function(o){
7514 conn.handleResponse(o, trans);
7517 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
7519 if(this.autoAbort !== false){
7523 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
7525 var script = document.createElement("script");
7526 script.setAttribute("src", url);
7527 script.setAttribute("type", "text/javascript");
7528 script.setAttribute("id", trans.scriptId);
7529 this.head.appendChild(script);
7533 callback.call(scope||this, null, arg, false);
7538 isLoading : function(){
7539 return this.trans ? true : false;
7543 * Abort the current server request.
7546 if(this.isLoading()){
7547 this.destroyTrans(this.trans);
7552 destroyTrans : function(trans, isLoaded){
7553 this.head.removeChild(document.getElementById(trans.scriptId));
7554 clearTimeout(trans.timeoutId);
7556 window[trans.cb] = undefined;
7558 delete window[trans.cb];
7561 // if hasn't been loaded, wait for load to remove it to prevent script error
7562 window[trans.cb] = function(){
7563 window[trans.cb] = undefined;
7565 delete window[trans.cb];
7572 handleResponse : function(o, trans){
7574 this.destroyTrans(trans, true);
7577 result = trans.reader.readRecords(o);
7579 this.fireEvent("loadexception", this, o, trans.arg, e);
7580 trans.callback.call(trans.scope||window, null, trans.arg, false);
7583 this.fireEvent("load", this, o, trans.arg);
7584 trans.callback.call(trans.scope||window, result, trans.arg, true);
7588 handleFailure : function(trans){
7590 this.destroyTrans(trans, false);
7591 this.fireEvent("loadexception", this, null, trans.arg);
7592 trans.callback.call(trans.scope||window, null, trans.arg, false);
7596 * Ext JS Library 1.1.1
7597 * Copyright(c) 2006-2007, Ext JS, LLC.
7599 * Originally Released Under LGPL - original licence link has changed is not relivant.
7602 * <script type="text/javascript">
7606 * @class Roo.data.JsonReader
7607 * @extends Roo.data.DataReader
7608 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
7609 * based on mappings in a provided Roo.data.Record constructor.
7611 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
7612 * in the reply previously.
7617 var RecordDef = Roo.data.Record.create([
7618 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
7619 {name: 'occupation'} // This field will use "occupation" as the mapping.
7621 var myReader = new Roo.data.JsonReader({
7622 totalProperty: "results", // The property which contains the total dataset size (optional)
7623 root: "rows", // The property which contains an Array of row objects
7624 id: "id" // The property within each row object that provides an ID for the record (optional)
7628 * This would consume a JSON file like this:
7630 { 'results': 2, 'rows': [
7631 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
7632 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
7635 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
7636 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
7637 * paged from the remote server.
7638 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
7639 * @cfg {String} root name of the property which contains the Array of row objects.
7640 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
7642 * Create a new JsonReader
7643 * @param {Object} meta Metadata configuration options
7644 * @param {Object} recordType Either an Array of field definition objects,
7645 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
7647 Roo.data.JsonReader = function(meta, recordType){
7650 // set some defaults:
7652 totalProperty: 'total',
7653 successProperty : 'success',
7658 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
7660 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
7663 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
7664 * Used by Store query builder to append _requestMeta to params.
7667 metaFromRemote : false,
7669 * This method is only used by a DataProxy which has retrieved data from a remote server.
7670 * @param {Object} response The XHR object which contains the JSON data in its responseText.
7671 * @return {Object} data A data block which is used by an Roo.data.Store object as
7672 * a cache of Roo.data.Records.
7674 read : function(response){
7675 var json = response.responseText;
7677 var o = /* eval:var:o */ eval("("+json+")");
7679 throw {message: "JsonReader.read: Json object not found"};
7685 this.metaFromRemote = true;
7686 this.meta = o.metaData;
7687 this.recordType = Roo.data.Record.create(o.metaData.fields);
7688 this.onMetaChange(this.meta, this.recordType, o);
7690 return this.readRecords(o);
7693 // private function a store will implement
7694 onMetaChange : function(meta, recordType, o){
7701 simpleAccess: function(obj, subsc) {
7708 getJsonAccessor: function(){
7710 return function(expr) {
7712 return(re.test(expr))
7713 ? new Function("obj", "return obj." + expr)
7723 * Create a data block containing Roo.data.Records from an XML document.
7724 * @param {Object} o An object which contains an Array of row objects in the property specified
7725 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
7726 * which contains the total size of the dataset.
7727 * @return {Object} data A data block which is used by an Roo.data.Store object as
7728 * a cache of Roo.data.Records.
7730 readRecords : function(o){
7732 * After any data loads, the raw JSON data is available for further custom processing.
7736 var s = this.meta, Record = this.recordType,
7737 f = Record.prototype.fields, fi = f.items, fl = f.length;
7739 // Generate extraction functions for the totalProperty, the root, the id, and for each field
7741 if(s.totalProperty) {
7742 this.getTotal = this.getJsonAccessor(s.totalProperty);
7744 if(s.successProperty) {
7745 this.getSuccess = this.getJsonAccessor(s.successProperty);
7747 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
7749 var g = this.getJsonAccessor(s.id);
7750 this.getId = function(rec) {
7752 return (r === undefined || r === "") ? null : r;
7755 this.getId = function(){return null;};
7758 for(var jj = 0; jj < fl; jj++){
7760 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
7761 this.ef[jj] = this.getJsonAccessor(map);
7765 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
7766 if(s.totalProperty){
7767 var vt = parseInt(this.getTotal(o), 10);
7772 if(s.successProperty){
7773 var vs = this.getSuccess(o);
7774 if(vs === false || vs === 'false'){
7779 for(var i = 0; i < c; i++){
7782 var id = this.getId(n);
7783 for(var j = 0; j < fl; j++){
7785 var v = this.ef[j](n);
7787 Roo.log('missing convert for ' + f.name);
7791 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
7793 var record = new Record(values, id);
7795 records[i] = record;
7801 totalRecords : totalRecords
7806 * Ext JS Library 1.1.1
7807 * Copyright(c) 2006-2007, Ext JS, LLC.
7809 * Originally Released Under LGPL - original licence link has changed is not relivant.
7812 * <script type="text/javascript">
7816 * @class Roo.data.ArrayReader
7817 * @extends Roo.data.DataReader
7818 * Data reader class to create an Array of Roo.data.Record objects from an Array.
7819 * Each element of that Array represents a row of data fields. The
7820 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
7821 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
7825 var RecordDef = Roo.data.Record.create([
7826 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
7827 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
7829 var myReader = new Roo.data.ArrayReader({
7830 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
7834 * This would consume an Array like this:
7836 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
7838 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
7840 * Create a new JsonReader
7841 * @param {Object} meta Metadata configuration options.
7842 * @param {Object} recordType Either an Array of field definition objects
7843 * as specified to {@link Roo.data.Record#create},
7844 * or an {@link Roo.data.Record} object
7845 * created using {@link Roo.data.Record#create}.
7847 Roo.data.ArrayReader = function(meta, recordType){
7848 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
7851 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
7853 * Create a data block containing Roo.data.Records from an XML document.
7854 * @param {Object} o An Array of row objects which represents the dataset.
7855 * @return {Object} data A data block which is used by an Roo.data.Store object as
7856 * a cache of Roo.data.Records.
7858 readRecords : function(o){
7859 var sid = this.meta ? this.meta.id : null;
7860 var recordType = this.recordType, fields = recordType.prototype.fields;
7863 for(var i = 0; i < root.length; i++){
7866 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
7867 for(var j = 0, jlen = fields.length; j < jlen; j++){
7868 var f = fields.items[j];
7869 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
7870 var v = n[k] !== undefined ? n[k] : f.defaultValue;
7874 var record = new recordType(values, id);
7876 records[records.length] = record;
7880 totalRecords : records.length
7889 * @class Roo.bootstrap.ComboBox
7890 * @extends Roo.bootstrap.TriggerField
7891 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
7892 * @cfg {Boolean} append (true|false) default false
7894 * Create a new ComboBox.
7895 * @param {Object} config Configuration options
7897 Roo.bootstrap.ComboBox = function(config){
7898 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
7902 * Fires when the dropdown list is expanded
7903 * @param {Roo.bootstrap.ComboBox} combo This combo box
7908 * Fires when the dropdown list is collapsed
7909 * @param {Roo.bootstrap.ComboBox} combo This combo box
7913 * @event beforeselect
7914 * Fires before a list item is selected. Return false to cancel the selection.
7915 * @param {Roo.bootstrap.ComboBox} combo This combo box
7916 * @param {Roo.data.Record} record The data record returned from the underlying store
7917 * @param {Number} index The index of the selected item in the dropdown list
7919 'beforeselect' : true,
7922 * Fires when a list item is selected
7923 * @param {Roo.bootstrap.ComboBox} combo This combo box
7924 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
7925 * @param {Number} index The index of the selected item in the dropdown list
7929 * @event beforequery
7930 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
7931 * The event object passed has these properties:
7932 * @param {Roo.bootstrap.ComboBox} combo This combo box
7933 * @param {String} query The query
7934 * @param {Boolean} forceAll true to force "all" query
7935 * @param {Boolean} cancel true to cancel the query
7936 * @param {Object} e The query event object
7938 'beforequery': true,
7941 * Fires when the 'add' icon is pressed (add a listener to enable add button)
7942 * @param {Roo.bootstrap.ComboBox} combo This combo box
7947 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
7948 * @param {Roo.bootstrap.ComboBox} combo This combo box
7949 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
7954 * Fires when the remove value from the combobox array
7955 * @param {Roo.bootstrap.ComboBox} combo This combo box
7962 this.selectedIndex = -1;
7963 if(this.mode == 'local'){
7964 if(config.queryDelay === undefined){
7965 this.queryDelay = 10;
7967 if(config.minChars === undefined){
7973 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
7976 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
7977 * rendering into an Roo.Editor, defaults to false)
7980 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
7981 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
7984 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
7987 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
7988 * the dropdown list (defaults to undefined, with no header element)
7992 * @cfg {String/Roo.Template} tpl The template to use to render the output
7996 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
7998 listWidth: undefined,
8000 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
8001 * mode = 'remote' or 'text' if mode = 'local')
8003 displayField: undefined,
8005 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
8006 * mode = 'remote' or 'value' if mode = 'local').
8007 * Note: use of a valueField requires the user make a selection
8008 * in order for a value to be mapped.
8010 valueField: undefined,
8014 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
8015 * field's data value (defaults to the underlying DOM element's name)
8017 hiddenName: undefined,
8019 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
8023 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
8025 selectedClass: 'active',
8028 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
8032 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
8033 * anchor positions (defaults to 'tl-bl')
8035 listAlign: 'tl-bl?',
8037 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
8041 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
8042 * query specified by the allQuery config option (defaults to 'query')
8044 triggerAction: 'query',
8046 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
8047 * (defaults to 4, does not apply if editable = false)
8051 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
8052 * delay (typeAheadDelay) if it matches a known value (defaults to false)
8056 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
8057 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
8061 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
8062 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
8066 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
8067 * when editable = true (defaults to false)
8069 selectOnFocus:false,
8071 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
8073 queryParam: 'query',
8075 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
8076 * when mode = 'remote' (defaults to 'Loading...')
8078 loadingText: 'Loading...',
8080 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
8084 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
8088 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
8089 * traditional select (defaults to true)
8093 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
8097 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
8101 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
8102 * listWidth has a higher value)
8106 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
8107 * allow the user to set arbitrary text into the field (defaults to false)
8109 forceSelection:false,
8111 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
8112 * if typeAhead = true (defaults to 250)
8114 typeAheadDelay : 250,
8116 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
8117 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
8119 valueNotFoundText : undefined,
8121 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
8126 * @cfg {Boolean} disableClear Disable showing of clear button.
8128 disableClear : false,
8130 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
8132 alwaysQuery : false,
8135 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
8149 // element that contains real text value.. (when hidden is used..)
8152 initEvents: function(){
8155 throw "can not find store for combo";
8157 this.store = Roo.factory(this.store, Roo.data);
8161 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
8164 if(this.hiddenName){
8166 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
8168 this.hiddenField.dom.value =
8169 this.hiddenValue !== undefined ? this.hiddenValue :
8170 this.value !== undefined ? this.value : '';
8172 // prevent input submission
8173 this.el.dom.removeAttribute('name');
8174 this.hiddenField.dom.setAttribute('name', this.hiddenName);
8179 // this.el.dom.setAttribute('autocomplete', 'off');
8182 var cls = 'x-combo-list';
8183 this.list = this.el.select('ul.dropdown-menu',true).first();
8185 //this.list = new Roo.Layer({
8186 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
8189 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
8190 this.list.setWidth(lw);
8192 this.list.on('mouseover', this.onViewOver, this);
8193 this.list.on('mousemove', this.onViewMove, this);
8195 this.list.on('scroll', this.onViewScroll, this);
8198 this.list.swallowEvent('mousewheel');
8199 this.assetHeight = 0;
8202 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
8203 this.assetHeight += this.header.getHeight();
8206 this.innerList = this.list.createChild({cls:cls+'-inner'});
8207 this.innerList.on('mouseover', this.onViewOver, this);
8208 this.innerList.on('mousemove', this.onViewMove, this);
8209 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
8211 if(this.allowBlank && !this.pageSize && !this.disableClear){
8212 this.footer = this.list.createChild({cls:cls+'-ft'});
8213 this.pageTb = new Roo.Toolbar(this.footer);
8217 this.footer = this.list.createChild({cls:cls+'-ft'});
8218 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
8219 {pageSize: this.pageSize});
8223 if (this.pageTb && this.allowBlank && !this.disableClear) {
8225 this.pageTb.add(new Roo.Toolbar.Fill(), {
8226 cls: 'x-btn-icon x-btn-clear',
8232 _this.onSelect(false, -1);
8237 this.assetHeight += this.footer.getHeight();
8242 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
8245 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
8246 singleSelect:true, store: this.store, selectedClass: this.selectedClass
8248 //this.view.wrapEl.setDisplayed(false);
8249 this.view.on('click', this.onViewClick, this);
8253 this.store.on('beforeload', this.onBeforeLoad, this);
8254 this.store.on('load', this.onLoad, this);
8255 this.store.on('loadexception', this.onLoadException, this);
8258 this.resizer = new Roo.Resizable(this.list, {
8259 pinned:true, handles:'se'
8261 this.resizer.on('resize', function(r, w, h){
8262 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
8264 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
8265 this.restrictHeight();
8267 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
8271 this.editable = true;
8272 this.setEditable(false);
8277 if (typeof(this.events.add.listeners) != 'undefined') {
8279 this.addicon = this.wrap.createChild(
8280 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
8282 this.addicon.on('click', function(e) {
8283 this.fireEvent('add', this);
8286 if (typeof(this.events.edit.listeners) != 'undefined') {
8288 this.editicon = this.wrap.createChild(
8289 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
8291 this.editicon.setStyle('margin-left', '40px');
8293 this.editicon.on('click', function(e) {
8295 // we fire even if inothing is selected..
8296 this.fireEvent('edit', this, this.lastData );
8302 this.keyNav = new Roo.KeyNav(this.inputEl(), {
8304 this.inKeyMode = true;
8308 "down" : function(e){
8309 if(!this.isExpanded()){
8310 this.onTriggerClick();
8312 this.inKeyMode = true;
8317 "enter" : function(e){
8322 "esc" : function(e){
8326 "tab" : function(e){
8329 if(this.fireEvent("specialkey", this, e)){
8330 this.onViewClick(false);
8338 doRelay : function(foo, bar, hname){
8339 if(hname == 'down' || this.scope.isExpanded()){
8340 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
8349 this.queryDelay = Math.max(this.queryDelay || 10,
8350 this.mode == 'local' ? 10 : 250);
8353 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
8356 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
8358 if(this.editable !== false){
8359 this.inputEl().on("keyup", this.onKeyUp, this);
8361 if(this.forceSelection){
8362 this.on('blur', this.doForce, this);
8366 this.choices = this.el.select('ul.select2-choices', true).first();
8367 this.searchField = this.el.select('ul li.select2-search-field', true).first();
8371 onDestroy : function(){
8373 this.view.setStore(null);
8374 this.view.el.removeAllListeners();
8375 this.view.el.remove();
8376 this.view.purgeListeners();
8379 this.list.dom.innerHTML = '';
8382 this.store.un('beforeload', this.onBeforeLoad, this);
8383 this.store.un('load', this.onLoad, this);
8384 this.store.un('loadexception', this.onLoadException, this);
8386 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
8390 fireKey : function(e){
8391 if(e.isNavKeyPress() && !this.list.isVisible()){
8392 this.fireEvent("specialkey", this, e);
8397 onResize: function(w, h){
8398 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
8400 // if(typeof w != 'number'){
8401 // // we do not handle it!?!?
8404 // var tw = this.trigger.getWidth();
8405 // // tw += this.addicon ? this.addicon.getWidth() : 0;
8406 // // tw += this.editicon ? this.editicon.getWidth() : 0;
8408 // this.inputEl().setWidth( this.adjustWidth('input', x));
8410 // //this.trigger.setStyle('left', x+'px');
8412 // if(this.list && this.listWidth === undefined){
8413 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
8414 // this.list.setWidth(lw);
8415 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
8423 * Allow or prevent the user from directly editing the field text. If false is passed,
8424 * the user will only be able to select from the items defined in the dropdown list. This method
8425 * is the runtime equivalent of setting the 'editable' config option at config time.
8426 * @param {Boolean} value True to allow the user to directly edit the field text
8428 setEditable : function(value){
8429 if(value == this.editable){
8432 this.editable = value;
8434 this.inputEl().dom.setAttribute('readOnly', true);
8435 this.inputEl().on('mousedown', this.onTriggerClick, this);
8436 this.inputEl().addClass('x-combo-noedit');
8438 this.inputEl().dom.setAttribute('readOnly', false);
8439 this.inputEl().un('mousedown', this.onTriggerClick, this);
8440 this.inputEl().removeClass('x-combo-noedit');
8446 onBeforeLoad : function(combo,opts){
8451 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
8453 this.restrictHeight();
8454 this.selectedIndex = -1;
8458 onLoad : function(){
8460 this.hasQuery = false;
8466 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
8467 this.loading.hide();
8470 if(this.store.getCount() > 0){
8472 this.restrictHeight();
8473 if(this.lastQuery == this.allQuery){
8475 this.inputEl().dom.select();
8477 if(!this.selectByValue(this.value, true)){
8478 this.select(0, true);
8482 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
8483 this.taTask.delay(this.typeAheadDelay);
8487 this.onEmptyResults();
8493 onLoadException : function()
8495 this.hasQuery = false;
8497 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
8498 this.loading.hide();
8502 Roo.log(this.store.reader.jsonData);
8503 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
8505 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
8511 onTypeAhead : function(){
8512 if(this.store.getCount() > 0){
8513 var r = this.store.getAt(0);
8514 var newValue = r.data[this.displayField];
8515 var len = newValue.length;
8516 var selStart = this.getRawValue().length;
8518 if(selStart != len){
8519 this.setRawValue(newValue);
8520 this.selectText(selStart, newValue.length);
8526 onSelect : function(record, index){
8528 if(this.fireEvent('beforeselect', this, record, index) !== false){
8530 this.setFromData(index > -1 ? record.data : false);
8533 this.fireEvent('select', this, record, index);
8538 * Returns the currently selected field value or empty string if no value is set.
8539 * @return {String} value The selected value
8541 getValue : function(){
8544 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
8547 if(this.valueField){
8548 return typeof this.value != 'undefined' ? this.value : '';
8550 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
8555 * Clears any text/value currently set in the field
8557 clearValue : function(){
8558 if(this.hiddenField){
8559 this.hiddenField.dom.value = '';
8562 this.setRawValue('');
8563 this.lastSelectionText = '';
8568 * Sets the specified value into the field. If the value finds a match, the corresponding record text
8569 * will be displayed in the field. If the value does not match the data value of an existing item,
8570 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
8571 * Otherwise the field will be blank (although the value will still be set).
8572 * @param {String} value The value to match
8574 setValue : function(v){
8581 if(this.valueField){
8582 var r = this.findRecord(this.valueField, v);
8584 text = r.data[this.displayField];
8585 }else if(this.valueNotFoundText !== undefined){
8586 text = this.valueNotFoundText;
8589 this.lastSelectionText = text;
8590 if(this.hiddenField){
8591 this.hiddenField.dom.value = v;
8593 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
8597 * @property {Object} the last set data for the element
8602 * Sets the value of the field based on a object which is related to the record format for the store.
8603 * @param {Object} value the value to set as. or false on reset?
8605 setFromData : function(o){
8612 var dv = ''; // display value
8613 var vv = ''; // value value..
8615 if (this.displayField) {
8616 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
8618 // this is an error condition!!!
8619 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
8622 if(this.valueField){
8623 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
8626 if(this.hiddenField){
8627 this.hiddenField.dom.value = vv;
8629 this.lastSelectionText = dv;
8630 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
8634 // no hidden field.. - we store the value in 'value', but still display
8635 // display field!!!!
8636 this.lastSelectionText = dv;
8637 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
8644 // overridden so that last data is reset..
8645 this.setValue(this.originalValue);
8646 this.clearInvalid();
8647 this.lastData = false;
8649 this.view.clearSelections();
8653 findRecord : function(prop, value){
8655 if(this.store.getCount() > 0){
8656 this.store.each(function(r){
8657 if(r.data[prop] == value){
8669 // returns hidden if it's set..
8670 if (!this.rendered) {return ''};
8671 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
8675 onViewMove : function(e, t){
8676 this.inKeyMode = false;
8680 onViewOver : function(e, t){
8681 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
8684 var item = this.view.findItemFromChild(t);
8686 var index = this.view.indexOf(item);
8687 this.select(index, false);
8692 onViewClick : function(doFocus)
8694 var index = this.view.getSelectedIndexes()[0];
8695 var r = this.store.getAt(index);
8697 this.onSelect(r, index);
8699 if(doFocus !== false && !this.blockFocus){
8700 this.inputEl().focus();
8705 restrictHeight : function(){
8706 //this.innerList.dom.style.height = '';
8707 //var inner = this.innerList.dom;
8708 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
8709 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
8710 //this.list.beginUpdate();
8711 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
8712 this.list.alignTo(this.inputEl(), this.listAlign);
8713 //this.list.endUpdate();
8717 onEmptyResults : function(){
8722 * Returns true if the dropdown list is expanded, else false.
8724 isExpanded : function(){
8725 return this.list.isVisible();
8729 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
8730 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
8731 * @param {String} value The data value of the item to select
8732 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
8733 * selected item if it is not currently in view (defaults to true)
8734 * @return {Boolean} True if the value matched an item in the list, else false
8736 selectByValue : function(v, scrollIntoView){
8737 if(v !== undefined && v !== null){
8738 var r = this.findRecord(this.valueField || this.displayField, v);
8740 this.select(this.store.indexOf(r), scrollIntoView);
8748 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
8749 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
8750 * @param {Number} index The zero-based index of the list item to select
8751 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
8752 * selected item if it is not currently in view (defaults to true)
8754 select : function(index, scrollIntoView){
8755 this.selectedIndex = index;
8756 this.view.select(index);
8757 if(scrollIntoView !== false){
8758 var el = this.view.getNode(index);
8760 //this.innerList.scrollChildIntoView(el, false);
8767 selectNext : function(){
8768 var ct = this.store.getCount();
8770 if(this.selectedIndex == -1){
8772 }else if(this.selectedIndex < ct-1){
8773 this.select(this.selectedIndex+1);
8779 selectPrev : function(){
8780 var ct = this.store.getCount();
8782 if(this.selectedIndex == -1){
8784 }else if(this.selectedIndex != 0){
8785 this.select(this.selectedIndex-1);
8791 onKeyUp : function(e){
8792 if(this.editable !== false && !e.isSpecialKey()){
8793 this.lastKey = e.getKey();
8794 this.dqTask.delay(this.queryDelay);
8799 validateBlur : function(){
8800 return !this.list || !this.list.isVisible();
8804 initQuery : function(){
8805 this.doQuery(this.getRawValue());
8809 doForce : function(){
8810 if(this.el.dom.value.length > 0){
8812 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
8818 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
8819 * query allowing the query action to be canceled if needed.
8820 * @param {String} query The SQL query to execute
8821 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
8822 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
8823 * saved in the current store (defaults to false)
8825 doQuery : function(q, forceAll){
8827 if(q === undefined || q === null){
8836 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
8841 forceAll = qe.forceAll;
8842 if(forceAll === true || (q.length >= this.minChars)){
8844 this.hasQuery = true;
8846 if(this.lastQuery != q || this.alwaysQuery){
8848 if(this.mode == 'local'){
8849 this.selectedIndex = -1;
8851 this.store.clearFilter();
8853 this.store.filter(this.displayField, q);
8857 this.store.baseParams[this.queryParam] = q;
8859 var options = {params : this.getParams(q)};
8863 options.params.start = this.page * this.pageSize;
8866 this.store.load(options);
8870 this.selectedIndex = -1;
8875 this.loadNext = false;
8879 getParams : function(q){
8881 //p[this.queryParam] = q;
8885 p.limit = this.pageSize;
8891 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
8893 collapse : function(){
8894 if(!this.isExpanded()){
8899 Roo.get(document).un('mousedown', this.collapseIf, this);
8900 Roo.get(document).un('mousewheel', this.collapseIf, this);
8901 if (!this.editable) {
8902 Roo.get(document).un('keydown', this.listKeyPress, this);
8904 this.fireEvent('collapse', this);
8908 collapseIf : function(e){
8909 var in_combo = e.within(this.el);
8910 var in_list = e.within(this.list);
8912 if (in_combo || in_list) {
8913 //e.stopPropagation();
8922 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
8924 expand : function(){
8926 if(this.isExpanded() || !this.hasFocus){
8930 this.list.alignTo(this.inputEl(), this.listAlign);
8932 Roo.get(document).on('mousedown', this.collapseIf, this);
8933 Roo.get(document).on('mousewheel', this.collapseIf, this);
8934 if (!this.editable) {
8935 Roo.get(document).on('keydown', this.listKeyPress, this);
8938 this.fireEvent('expand', this);
8942 // Implements the default empty TriggerField.onTriggerClick function
8943 onTriggerClick : function()
8945 Roo.log('trigger click');
8952 this.loadNext = false;
8954 if(this.isExpanded()){
8956 if (!this.blockFocus) {
8957 this.inputEl().focus();
8961 this.hasFocus = true;
8962 if(this.triggerAction == 'all') {
8963 this.doQuery(this.allQuery, true);
8965 this.doQuery(this.getRawValue());
8967 if (!this.blockFocus) {
8968 this.inputEl().focus();
8972 listKeyPress : function(e)
8974 //Roo.log('listkeypress');
8975 // scroll to first matching element based on key pres..
8976 if (e.isSpecialKey()) {
8979 var k = String.fromCharCode(e.getKey()).toUpperCase();
8982 var csel = this.view.getSelectedNodes();
8983 var cselitem = false;
8985 var ix = this.view.indexOf(csel[0]);
8986 cselitem = this.store.getAt(ix);
8987 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
8993 this.store.each(function(v) {
8995 // start at existing selection.
8996 if (cselitem.id == v.id) {
9002 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
9003 match = this.store.indexOf(v);
9009 if (match === false) {
9010 return true; // no more action?
9013 this.view.select(match);
9014 var sn = Roo.get(this.view.getSelectedNodes()[0])
9015 //sn.scrollIntoView(sn.dom.parentNode, false);
9018 onViewScroll : function(e, t){
9020 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
9024 this.hasQuery = true;
9026 this.loading = this.list.select('.loading', true).first();
9028 if(this.loading === null){
9029 this.list.createChild({
9031 cls: 'loading select2-more-results select2-active',
9032 html: 'Loading more results...'
9035 this.loading = this.list.select('.loading', true).first();
9037 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
9039 this.loading.hide();
9042 this.loading.show();
9047 this.loadNext = true;
9049 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
9054 addItem : function(o)
9056 var dv = ''; // display value
9058 if (this.displayField) {
9059 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
9061 // this is an error condition!!!
9062 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
9069 var choice = this.choices.createChild({
9071 cls: 'select2-search-choice',
9080 cls: 'select2-search-choice-close',
9085 }, this.searchField);
9087 var close = choice.select('a.select2-search-choice-close', true).first()
9089 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
9096 this.inputEl().dom.value = '';
9100 onRemoveItem : function(e, _self, o)
9102 Roo.log('remove item');
9103 var index = this.item.indexOf(o.data) * 1;
9106 Roo.log('not this item?!');
9110 this.item.splice(index, 1);
9115 this.fireEvent('remove', this);
9119 syncValue : function()
9121 if(!this.item.length){
9128 Roo.each(this.item, function(i){
9129 if(_this.valueField){
9130 value.push(i[_this.valueField]);
9137 this.value = value.join(',');
9139 if(this.hiddenField){
9140 this.hiddenField.dom.value = this.value;
9144 clearItem : function()
9152 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
9162 * @cfg {Boolean} grow
9166 * @cfg {Number} growMin
9170 * @cfg {Number} growMax
9180 * Ext JS Library 1.1.1
9181 * Copyright(c) 2006-2007, Ext JS, LLC.
9183 * Originally Released Under LGPL - original licence link has changed is not relivant.
9186 * <script type="text/javascript">
9191 * @extends Roo.util.Observable
9192 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
9193 * This class also supports single and multi selection modes. <br>
9194 * Create a data model bound view:
9196 var store = new Roo.data.Store(...);
9198 var view = new Roo.View({
9200 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
9203 selectedClass: "ydataview-selected",
9207 // listen for node click?
9208 view.on("click", function(vw, index, node, e){
9209 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9213 dataModel.load("foobar.xml");
9215 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
9217 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
9218 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
9220 * Note: old style constructor is still suported (container, template, config)
9224 * @param {Object} config The config object
9227 Roo.View = function(config, depreciated_tpl, depreciated_config){
9229 if (typeof(depreciated_tpl) == 'undefined') {
9230 // new way.. - universal constructor.
9231 Roo.apply(this, config);
9232 this.el = Roo.get(this.el);
9235 this.el = Roo.get(config);
9236 this.tpl = depreciated_tpl;
9237 Roo.apply(this, depreciated_config);
9239 this.wrapEl = this.el.wrap().wrap();
9240 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
9243 if(typeof(this.tpl) == "string"){
9244 this.tpl = new Roo.Template(this.tpl);
9246 // support xtype ctors..
9247 this.tpl = new Roo.factory(this.tpl, Roo);
9259 * @event beforeclick
9260 * Fires before a click is processed. Returns false to cancel the default action.
9261 * @param {Roo.View} this
9262 * @param {Number} index The index of the target node
9263 * @param {HTMLElement} node The target node
9264 * @param {Roo.EventObject} e The raw event object
9266 "beforeclick" : true,
9269 * Fires when a template node is clicked.
9270 * @param {Roo.View} this
9271 * @param {Number} index The index of the target node
9272 * @param {HTMLElement} node The target node
9273 * @param {Roo.EventObject} e The raw event object
9278 * Fires when a template node is double clicked.
9279 * @param {Roo.View} this
9280 * @param {Number} index The index of the target node
9281 * @param {HTMLElement} node The target node
9282 * @param {Roo.EventObject} e The raw event object
9286 * @event contextmenu
9287 * Fires when a template node is right clicked.
9288 * @param {Roo.View} this
9289 * @param {Number} index The index of the target node
9290 * @param {HTMLElement} node The target node
9291 * @param {Roo.EventObject} e The raw event object
9293 "contextmenu" : true,
9295 * @event selectionchange
9296 * Fires when the selected nodes change.
9297 * @param {Roo.View} this
9298 * @param {Array} selections Array of the selected nodes
9300 "selectionchange" : true,
9303 * @event beforeselect
9304 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
9305 * @param {Roo.View} this
9306 * @param {HTMLElement} node The node to be selected
9307 * @param {Array} selections Array of currently selected nodes
9309 "beforeselect" : true,
9311 * @event preparedata
9312 * Fires on every row to render, to allow you to change the data.
9313 * @param {Roo.View} this
9314 * @param {Object} data to be rendered (change this)
9316 "preparedata" : true
9324 "click": this.onClick,
9325 "dblclick": this.onDblClick,
9326 "contextmenu": this.onContextMenu,
9330 this.selections = [];
9332 this.cmp = new Roo.CompositeElementLite([]);
9334 this.store = Roo.factory(this.store, Roo.data);
9335 this.setStore(this.store, true);
9338 if ( this.footer && this.footer.xtype) {
9340 var fctr = this.wrapEl.appendChild(document.createElement("div"));
9342 this.footer.dataSource = this.store
9343 this.footer.container = fctr;
9344 this.footer = Roo.factory(this.footer, Roo);
9345 fctr.insertFirst(this.el);
9347 // this is a bit insane - as the paging toolbar seems to detach the el..
9348 // dom.parentNode.parentNode.parentNode
9349 // they get detached?
9353 Roo.View.superclass.constructor.call(this);
9358 Roo.extend(Roo.View, Roo.util.Observable, {
9361 * @cfg {Roo.data.Store} store Data store to load data from.
9366 * @cfg {String|Roo.Element} el The container element.
9371 * @cfg {String|Roo.Template} tpl The template used by this View
9375 * @cfg {String} dataName the named area of the template to use as the data area
9376 * Works with domtemplates roo-name="name"
9380 * @cfg {String} selectedClass The css class to add to selected nodes
9382 selectedClass : "x-view-selected",
9384 * @cfg {String} emptyText The empty text to show when nothing is loaded.
9389 * @cfg {String} text to display on mask (default Loading)
9393 * @cfg {Boolean} multiSelect Allow multiple selection
9395 multiSelect : false,
9397 * @cfg {Boolean} singleSelect Allow single selection
9399 singleSelect: false,
9402 * @cfg {Boolean} toggleSelect - selecting
9404 toggleSelect : false,
9407 * Returns the element this view is bound to.
9408 * @return {Roo.Element}
9417 * Refreshes the view. - called by datachanged on the store. - do not call directly.
9419 refresh : function(){
9423 // if we are using something like 'domtemplate', then
9424 // the what gets used is:
9425 // t.applySubtemplate(NAME, data, wrapping data..)
9426 // the outer template then get' applied with
9427 // the store 'extra data'
9428 // and the body get's added to the
9429 // roo-name="data" node?
9430 // <span class='roo-tpl-{name}'></span> ?????
9434 this.clearSelections();
9437 var records = this.store.getRange();
9438 if(records.length < 1) {
9440 // is this valid?? = should it render a template??
9442 this.el.update(this.emptyText);
9446 if (this.dataName) {
9447 this.el.update(t.apply(this.store.meta)); //????
9448 el = this.el.child('.roo-tpl-' + this.dataName);
9451 for(var i = 0, len = records.length; i < len; i++){
9452 var data = this.prepareData(records[i].data, i, records[i]);
9453 this.fireEvent("preparedata", this, data, i, records[i]);
9454 html[html.length] = Roo.util.Format.trim(
9456 t.applySubtemplate(this.dataName, data, this.store.meta) :
9463 el.update(html.join(""));
9464 this.nodes = el.dom.childNodes;
9465 this.updateIndexes(0);
9470 * Function to override to reformat the data that is sent to
9471 * the template for each node.
9472 * DEPRICATED - use the preparedata event handler.
9473 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
9474 * a JSON object for an UpdateManager bound view).
9476 prepareData : function(data, index, record)
9478 this.fireEvent("preparedata", this, data, index, record);
9482 onUpdate : function(ds, record){
9483 Roo.log('on update');
9484 this.clearSelections();
9485 var index = this.store.indexOf(record);
9486 var n = this.nodes[index];
9487 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
9488 n.parentNode.removeChild(n);
9489 this.updateIndexes(index, index);
9495 onAdd : function(ds, records, index)
9497 Roo.log(['on Add', ds, records, index] );
9498 this.clearSelections();
9499 if(this.nodes.length == 0){
9503 var n = this.nodes[index];
9504 for(var i = 0, len = records.length; i < len; i++){
9505 var d = this.prepareData(records[i].data, i, records[i]);
9507 this.tpl.insertBefore(n, d);
9510 this.tpl.append(this.el, d);
9513 this.updateIndexes(index);
9516 onRemove : function(ds, record, index){
9517 Roo.log('onRemove');
9518 this.clearSelections();
9519 var el = this.dataName ?
9520 this.el.child('.roo-tpl-' + this.dataName) :
9523 el.dom.removeChild(this.nodes[index]);
9524 this.updateIndexes(index);
9528 * Refresh an individual node.
9529 * @param {Number} index
9531 refreshNode : function(index){
9532 this.onUpdate(this.store, this.store.getAt(index));
9535 updateIndexes : function(startIndex, endIndex){
9536 var ns = this.nodes;
9537 startIndex = startIndex || 0;
9538 endIndex = endIndex || ns.length - 1;
9539 for(var i = startIndex; i <= endIndex; i++){
9540 ns[i].nodeIndex = i;
9545 * Changes the data store this view uses and refresh the view.
9546 * @param {Store} store
9548 setStore : function(store, initial){
9549 if(!initial && this.store){
9550 this.store.un("datachanged", this.refresh);
9551 this.store.un("add", this.onAdd);
9552 this.store.un("remove", this.onRemove);
9553 this.store.un("update", this.onUpdate);
9554 this.store.un("clear", this.refresh);
9555 this.store.un("beforeload", this.onBeforeLoad);
9556 this.store.un("load", this.onLoad);
9557 this.store.un("loadexception", this.onLoad);
9561 store.on("datachanged", this.refresh, this);
9562 store.on("add", this.onAdd, this);
9563 store.on("remove", this.onRemove, this);
9564 store.on("update", this.onUpdate, this);
9565 store.on("clear", this.refresh, this);
9566 store.on("beforeload", this.onBeforeLoad, this);
9567 store.on("load", this.onLoad, this);
9568 store.on("loadexception", this.onLoad, this);
9576 * onbeforeLoad - masks the loading area.
9579 onBeforeLoad : function(store,opts)
9581 Roo.log('onBeforeLoad');
9585 this.el.mask(this.mask ? this.mask : "Loading" );
9587 onLoad : function ()
9594 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
9595 * @param {HTMLElement} node
9596 * @return {HTMLElement} The template node
9598 findItemFromChild : function(node){
9599 var el = this.dataName ?
9600 this.el.child('.roo-tpl-' + this.dataName,true) :
9603 if(!node || node.parentNode == el){
9606 var p = node.parentNode;
9607 while(p && p != el){
9608 if(p.parentNode == el){
9617 onClick : function(e){
9618 var item = this.findItemFromChild(e.getTarget());
9620 var index = this.indexOf(item);
9621 if(this.onItemClick(item, index, e) !== false){
9622 this.fireEvent("click", this, index, item, e);
9625 this.clearSelections();
9630 onContextMenu : function(e){
9631 var item = this.findItemFromChild(e.getTarget());
9633 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
9638 onDblClick : function(e){
9639 var item = this.findItemFromChild(e.getTarget());
9641 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
9645 onItemClick : function(item, index, e)
9647 if(this.fireEvent("beforeclick", this, index, item, e) === false){
9650 if (this.toggleSelect) {
9651 var m = this.isSelected(item) ? 'unselect' : 'select';
9654 _t[m](item, true, false);
9657 if(this.multiSelect || this.singleSelect){
9658 if(this.multiSelect && e.shiftKey && this.lastSelection){
9659 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
9661 this.select(item, this.multiSelect && e.ctrlKey);
9662 this.lastSelection = item;
9670 * Get the number of selected nodes.
9673 getSelectionCount : function(){
9674 return this.selections.length;
9678 * Get the currently selected nodes.
9679 * @return {Array} An array of HTMLElements
9681 getSelectedNodes : function(){
9682 return this.selections;
9686 * Get the indexes of the selected nodes.
9689 getSelectedIndexes : function(){
9690 var indexes = [], s = this.selections;
9691 for(var i = 0, len = s.length; i < len; i++){
9692 indexes.push(s[i].nodeIndex);
9698 * Clear all selections
9699 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
9701 clearSelections : function(suppressEvent){
9702 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
9703 this.cmp.elements = this.selections;
9704 this.cmp.removeClass(this.selectedClass);
9705 this.selections = [];
9707 this.fireEvent("selectionchange", this, this.selections);
9713 * Returns true if the passed node is selected
9714 * @param {HTMLElement/Number} node The node or node index
9717 isSelected : function(node){
9718 var s = this.selections;
9722 node = this.getNode(node);
9723 return s.indexOf(node) !== -1;
9728 * @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
9729 * @param {Boolean} keepExisting (optional) true to keep existing selections
9730 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
9732 select : function(nodeInfo, keepExisting, suppressEvent){
9733 if(nodeInfo instanceof Array){
9735 this.clearSelections(true);
9737 for(var i = 0, len = nodeInfo.length; i < len; i++){
9738 this.select(nodeInfo[i], true, true);
9742 var node = this.getNode(nodeInfo);
9743 if(!node || this.isSelected(node)){
9744 return; // already selected.
9747 this.clearSelections(true);
9749 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
9750 Roo.fly(node).addClass(this.selectedClass);
9751 this.selections.push(node);
9753 this.fireEvent("selectionchange", this, this.selections);
9761 * @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
9762 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
9763 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
9765 unselect : function(nodeInfo, keepExisting, suppressEvent)
9767 if(nodeInfo instanceof Array){
9768 Roo.each(this.selections, function(s) {
9769 this.unselect(s, nodeInfo);
9773 var node = this.getNode(nodeInfo);
9774 if(!node || !this.isSelected(node)){
9775 Roo.log("not selected");
9776 return; // not selected.
9780 Roo.each(this.selections, function(s) {
9782 Roo.fly(node).removeClass(this.selectedClass);
9789 this.selections= ns;
9790 this.fireEvent("selectionchange", this, this.selections);
9794 * Gets a template node.
9795 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9796 * @return {HTMLElement} The node or null if it wasn't found
9798 getNode : function(nodeInfo){
9799 if(typeof nodeInfo == "string"){
9800 return document.getElementById(nodeInfo);
9801 }else if(typeof nodeInfo == "number"){
9802 return this.nodes[nodeInfo];
9808 * Gets a range template nodes.
9809 * @param {Number} startIndex
9810 * @param {Number} endIndex
9811 * @return {Array} An array of nodes
9813 getNodes : function(start, end){
9814 var ns = this.nodes;
9816 end = typeof end == "undefined" ? ns.length - 1 : end;
9819 for(var i = start; i <= end; i++){
9823 for(var i = start; i >= end; i--){
9831 * Finds the index of the passed node
9832 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9833 * @return {Number} The index of the node or -1
9835 indexOf : function(node){
9836 node = this.getNode(node);
9837 if(typeof node.nodeIndex == "number"){
9838 return node.nodeIndex;
9840 var ns = this.nodes;
9841 for(var i = 0, len = ns.length; i < len; i++){
9852 * based on jquery fullcalendar
9856 Roo.bootstrap = Roo.bootstrap || {};
9858 * @class Roo.bootstrap.Calendar
9859 * @extends Roo.bootstrap.Component
9860 * Bootstrap Calendar class
9861 * @cfg {Boolean} loadMask (true|false) default false
9864 * Create a new Container
9865 * @param {Object} config The config object
9870 Roo.bootstrap.Calendar = function(config){
9871 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
9875 * Fires when a date is selected
9876 * @param {DatePicker} this
9877 * @param {Date} date The selected date
9881 * @event monthchange
9882 * Fires when the displayed month changes
9883 * @param {DatePicker} this
9884 * @param {Date} date The selected month
9886 'monthchange': true,
9889 * Fires when mouse over an event
9890 * @param {Calendar} this
9891 * @param {event} Event
9896 * Fires when the mouse leaves an
9897 * @param {Calendar} this
9903 * Fires when the mouse click an
9904 * @param {Calendar} this
9913 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
9916 * @cfg {Number} startDay
9917 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
9923 getAutoCreate : function(){
9926 var fc_button = function(name, corner, style, content ) {
9927 return Roo.apply({},{
9929 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
9931 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
9934 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
9942 style : 'width:100%',
9949 cls : 'fc-header-left',
9951 fc_button('prev', 'left', 'arrow', '‹' ),
9952 fc_button('next', 'right', 'arrow', '›' ),
9953 { tag: 'span', cls: 'fc-header-space' },
9954 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
9962 cls : 'fc-header-center',
9966 cls: 'fc-header-title',
9969 html : 'month / year'
9977 cls : 'fc-header-right',
9979 /* fc_button('month', 'left', '', 'month' ),
9980 fc_button('week', '', '', 'week' ),
9981 fc_button('day', 'right', '', 'day' )
9993 var cal_heads = function() {
9995 // fixme - handle this.
9997 for (var i =0; i < Date.dayNames.length; i++) {
9998 var d = Date.dayNames[i];
10001 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
10002 html : d.substring(0,3)
10006 ret[0].cls += ' fc-first';
10007 ret[6].cls += ' fc-last';
10010 var cal_cell = function(n) {
10013 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
10018 cls: 'fc-day-number',
10022 cls: 'fc-day-content',
10026 style: 'position: relative;' // height: 17px;
10038 var cal_rows = function() {
10041 for (var r = 0; r < 6; r++) {
10048 for (var i =0; i < Date.dayNames.length; i++) {
10049 var d = Date.dayNames[i];
10050 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
10053 row.cn[0].cls+=' fc-first';
10054 row.cn[0].cn[0].style = 'min-height:90px';
10055 row.cn[6].cls+=' fc-last';
10059 ret[0].cls += ' fc-first';
10060 ret[4].cls += ' fc-prev-last';
10061 ret[5].cls += ' fc-last';
10068 cls: 'fc-border-separate',
10069 style : 'width:100%',
10077 cls : 'fc-first fc-last',
10095 cls : 'fc-content',
10096 style : "position: relative;",
10099 cls : 'fc-view fc-view-month fc-grid',
10100 style : 'position: relative',
10101 unselectable : 'on',
10104 cls : 'fc-event-container',
10105 style : 'position:absolute;z-index:8;top:0;left:0;'
10123 initEvents : function()
10126 throw "can not find store for calendar";
10132 style: "text-align:center",
10136 style: "background-color:white;width:50%;margin:250 auto",
10140 src: rootURL + '/roojs1/images/ux/lightbox/loading.gif'
10151 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
10153 var size = this.el.select('.fc-content', true).first().getSize();
10154 this.maskEl.setSize(size.width, size.height);
10155 this.maskEl.enableDisplayMode("block");
10156 if(!this.loadMask){
10157 this.maskEl.hide();
10160 this.store = Roo.factory(this.store, Roo.data);
10161 this.store.on('load', this.onLoad, this);
10162 this.store.on('beforeload', this.onBeforeLoad, this);
10166 this.cells = this.el.select('.fc-day',true);
10167 //Roo.log(this.cells);
10168 this.textNodes = this.el.query('.fc-day-number');
10169 this.cells.addClassOnOver('fc-state-hover');
10171 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
10172 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
10173 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
10174 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
10176 this.on('monthchange', this.onMonthChange, this);
10178 this.update(new Date().clearTime());
10181 resize : function() {
10182 var sz = this.el.getSize();
10184 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
10185 this.el.select('.fc-day-content div',true).setHeight(34);
10190 showPrevMonth : function(e){
10191 this.update(this.activeDate.add("mo", -1));
10193 showToday : function(e){
10194 this.update(new Date().clearTime());
10197 showNextMonth : function(e){
10198 this.update(this.activeDate.add("mo", 1));
10202 showPrevYear : function(){
10203 this.update(this.activeDate.add("y", -1));
10207 showNextYear : function(){
10208 this.update(this.activeDate.add("y", 1));
10213 update : function(date)
10215 var vd = this.activeDate;
10216 this.activeDate = date;
10217 // if(vd && this.el){
10218 // var t = date.getTime();
10219 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
10220 // Roo.log('using add remove');
10222 // this.fireEvent('monthchange', this, date);
10224 // this.cells.removeClass("fc-state-highlight");
10225 // this.cells.each(function(c){
10226 // if(c.dateValue == t){
10227 // c.addClass("fc-state-highlight");
10228 // setTimeout(function(){
10229 // try{c.dom.firstChild.focus();}catch(e){}
10239 var days = date.getDaysInMonth();
10241 var firstOfMonth = date.getFirstDateOfMonth();
10242 var startingPos = firstOfMonth.getDay()-this.startDay;
10244 if(startingPos < this.startDay){
10248 var pm = date.add(Date.MONTH, -1);
10249 var prevStart = pm.getDaysInMonth()-startingPos;
10251 this.cells = this.el.select('.fc-day',true);
10252 this.textNodes = this.el.query('.fc-day-number');
10253 this.cells.addClassOnOver('fc-state-hover');
10255 var cells = this.cells.elements;
10256 var textEls = this.textNodes;
10258 Roo.each(cells, function(cell){
10259 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
10262 days += startingPos;
10264 // convert everything to numbers so it's fast
10265 var day = 86400000;
10266 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
10269 //Roo.log(prevStart);
10271 var today = new Date().clearTime().getTime();
10272 var sel = date.clearTime().getTime();
10273 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
10274 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
10275 var ddMatch = this.disabledDatesRE;
10276 var ddText = this.disabledDatesText;
10277 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
10278 var ddaysText = this.disabledDaysText;
10279 var format = this.format;
10281 var setCellClass = function(cal, cell){
10283 //Roo.log('set Cell Class');
10285 var t = d.getTime();
10289 cell.dateValue = t;
10291 cell.className += " fc-today";
10292 cell.className += " fc-state-highlight";
10293 cell.title = cal.todayText;
10296 // disable highlight in other month..
10297 //cell.className += " fc-state-highlight";
10302 cell.className = " fc-state-disabled";
10303 cell.title = cal.minText;
10307 cell.className = " fc-state-disabled";
10308 cell.title = cal.maxText;
10312 if(ddays.indexOf(d.getDay()) != -1){
10313 cell.title = ddaysText;
10314 cell.className = " fc-state-disabled";
10317 if(ddMatch && format){
10318 var fvalue = d.dateFormat(format);
10319 if(ddMatch.test(fvalue)){
10320 cell.title = ddText.replace("%0", fvalue);
10321 cell.className = " fc-state-disabled";
10325 if (!cell.initialClassName) {
10326 cell.initialClassName = cell.dom.className;
10329 cell.dom.className = cell.initialClassName + ' ' + cell.className;
10334 for(; i < startingPos; i++) {
10335 textEls[i].innerHTML = (++prevStart);
10336 d.setDate(d.getDate()+1);
10338 cells[i].className = "fc-past fc-other-month";
10339 setCellClass(this, cells[i]);
10344 for(; i < days; i++){
10345 intDay = i - startingPos + 1;
10346 textEls[i].innerHTML = (intDay);
10347 d.setDate(d.getDate()+1);
10349 cells[i].className = ''; // "x-date-active";
10350 setCellClass(this, cells[i]);
10354 for(; i < 42; i++) {
10355 textEls[i].innerHTML = (++extraDays);
10356 d.setDate(d.getDate()+1);
10358 cells[i].className = "fc-future fc-other-month";
10359 setCellClass(this, cells[i]);
10362 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
10364 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
10366 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
10367 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
10369 if(totalRows != 6){
10370 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
10371 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
10374 this.fireEvent('monthchange', this, date);
10378 if(!this.internalRender){
10379 var main = this.el.dom.firstChild;
10380 var w = main.offsetWidth;
10381 this.el.setWidth(w + this.el.getBorderWidth("lr"));
10382 Roo.fly(main).setWidth(w);
10383 this.internalRender = true;
10384 // opera does not respect the auto grow header center column
10385 // then, after it gets a width opera refuses to recalculate
10386 // without a second pass
10387 if(Roo.isOpera && !this.secondPass){
10388 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
10389 this.secondPass = true;
10390 this.update.defer(10, this, [date]);
10397 findCell : function(dt) {
10398 dt = dt.clearTime().getTime();
10400 this.cells.each(function(c){
10401 //Roo.log("check " +c.dateValue + '?=' + dt);
10402 if(c.dateValue == dt){
10412 findCells : function(ev) {
10413 var s = ev.start.clone().clearTime().getTime();
10415 var e= ev.end.clone().clearTime().getTime();
10418 this.cells.each(function(c){
10419 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
10421 if(c.dateValue > e){
10424 if(c.dateValue < s){
10433 findBestRow: function(cells)
10437 for (var i =0 ; i < cells.length;i++) {
10438 ret = Math.max(cells[i].rows || 0,ret);
10445 addItem : function(ev)
10447 // look for vertical location slot in
10448 var cells = this.findCells(ev);
10450 ev.row = this.findBestRow(cells);
10452 // work out the location.
10456 for(var i =0; i < cells.length; i++) {
10464 if (crow.start.getY() == cells[i].getY()) {
10466 crow.end = cells[i];
10482 for (var i = 0; i < cells.length;i++) {
10483 cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
10487 this.calevents.push(ev);
10490 clearEvents: function() {
10492 if(!this.calevents){
10496 Roo.each(this.cells.elements, function(c){
10500 Roo.each(this.calevents, function(e) {
10501 Roo.each(e.els, function(el) {
10502 el.un('mouseenter' ,this.onEventEnter, this);
10503 el.un('mouseleave' ,this.onEventLeave, this);
10510 renderEvents: function()
10512 // first make sure there is enough space..
10514 this.cells.each(function(c) {
10516 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.rows * 20));
10519 for (var e = 0; e < this.calevents.length; e++) {
10520 var ev = this.calevents[e];
10521 var cells = ev.cells;
10522 var rows = ev.rows;
10524 for(var i =0; i < rows.length; i++) {
10527 // how many rows should it span..
10530 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
10531 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
10533 unselectable : "on",
10536 cls: 'fc-event-inner',
10540 // cls: 'fc-event-time',
10541 // html : cells.length > 1 ? '' : ev.time
10545 cls: 'fc-event-title',
10546 html : String.format('{0}', ev.title)
10553 cls: 'ui-resizable-handle ui-resizable-e',
10554 html : '  '
10560 cfg.cls += ' fc-event-start';
10562 if ((i+1) == rows.length) {
10563 cfg.cls += ' fc-event-end';
10566 var ctr = this.el.select('.fc-event-container',true).first();
10567 var cg = ctr.createChild(cfg);
10569 cg.on('mouseenter' ,this.onEventEnter, this, ev);
10570 cg.on('mouseleave' ,this.onEventLeave, this, ev);
10571 cg.on('click', this.onEventClick, this, ev);
10575 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
10576 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
10578 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
10579 cg.setWidth(ebox.right - sbox.x -2);
10587 onEventEnter: function (e, el,event,d) {
10588 this.fireEvent('evententer', this, el, event);
10591 onEventLeave: function (e, el,event,d) {
10592 this.fireEvent('eventleave', this, el, event);
10595 onEventClick: function (e, el,event,d) {
10596 this.fireEvent('eventclick', this, el, event);
10599 onMonthChange: function () {
10603 onLoad: function ()
10605 this.calevents = [];
10608 if(this.store.getCount() > 0){
10609 this.store.data.each(function(d){
10612 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
10613 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
10614 time : d.data.start_time,
10615 title : d.data.title,
10616 description : d.data.description,
10617 venue : d.data.venue
10622 this.renderEvents();
10625 this.maskEl.hide();
10629 onBeforeLoad: function()
10631 this.clearEvents();
10634 this.maskEl.show();
10648 * @class Roo.bootstrap.Popover
10649 * @extends Roo.bootstrap.Component
10650 * Bootstrap Popover class
10651 * @cfg {String} html contents of the popover (or false to use children..)
10652 * @cfg {String} title of popover (or false to hide)
10653 * @cfg {String} placement how it is placed
10654 * @cfg {String} trigger click || hover (or false to trigger manually)
10655 * @cfg {String} over what (parent or false to trigger manually.)
10658 * Create a new Popover
10659 * @param {Object} config The config object
10662 Roo.bootstrap.Popover = function(config){
10663 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
10666 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
10668 title: 'Fill in a title',
10671 placement : 'right',
10672 trigger : 'hover', // hover
10676 can_build_overlaid : false,
10678 getChildContainer : function()
10680 return this.el.select('.popover-content',true).first();
10683 getAutoCreate : function(){
10684 Roo.log('make popover?');
10686 cls : 'popover roo-dynamic',
10687 style: 'display:block',
10693 cls : 'popover-inner',
10697 cls: 'popover-title',
10701 cls : 'popover-content',
10712 setTitle: function(str)
10714 this.el.select('.popover-title',true).first().dom.innerHTML = str;
10716 setContent: function(str)
10718 this.el.select('.popover-content',true).first().dom.innerHTML = str;
10720 // as it get's added to the bottom of the page.
10721 onRender : function(ct, position)
10723 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
10725 var cfg = Roo.apply({}, this.getAutoCreate());
10729 cfg.cls += ' ' + this.cls;
10732 cfg.style = this.style;
10734 Roo.log("adding to ")
10735 this.el = Roo.get(document.body).createChild(cfg, position);
10741 initEvents : function()
10743 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
10744 this.el.enableDisplayMode('block');
10746 if (this.over === false) {
10749 if (this.triggers === false) {
10752 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
10753 var triggers = this.trigger ? this.trigger.split(' ') : [];
10754 Roo.each(triggers, function(trigger) {
10756 if (trigger == 'click') {
10757 on_el.on('click', this.toggle, this);
10758 } else if (trigger != 'manual') {
10759 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
10760 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
10762 on_el.on(eventIn ,this.enter, this);
10763 on_el.on(eventOut, this.leave, this);
10774 toggle : function () {
10775 this.hoverState == 'in' ? this.leave() : this.enter();
10778 enter : function () {
10781 clearTimeout(this.timeout);
10783 this.hoverState = 'in'
10785 if (!this.delay || !this.delay.show) {
10790 this.timeout = setTimeout(function () {
10791 if (_t.hoverState == 'in') {
10794 }, this.delay.show)
10796 leave : function() {
10797 clearTimeout(this.timeout);
10799 this.hoverState = 'out'
10801 if (!this.delay || !this.delay.hide) {
10806 this.timeout = setTimeout(function () {
10807 if (_t.hoverState == 'out') {
10810 }, this.delay.hide)
10813 show : function (on_el)
10816 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
10819 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
10820 if (this.html !== false) {
10821 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
10823 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
10824 if (!this.title.length) {
10825 this.el.select('.popover-title',true).hide();
10828 var placement = typeof this.placement == 'function' ?
10829 this.placement.call(this, this.el, on_el) :
10832 var autoToken = /\s?auto?\s?/i;
10833 var autoPlace = autoToken.test(placement);
10835 placement = placement.replace(autoToken, '') || 'top';
10839 //this.el.setXY([0,0]);
10841 this.el.dom.style.display='block';
10842 this.el.addClass(placement);
10844 //this.el.appendTo(on_el);
10846 var p = this.getPosition();
10847 var box = this.el.getBox();
10852 var align = Roo.bootstrap.Popover.alignment[placement]
10853 this.el.alignTo(on_el, align[0],align[1]);
10854 //var arrow = this.el.select('.arrow',true).first();
10855 //arrow.set(align[2],
10857 this.el.addClass('in');
10858 this.hoverState = null;
10860 if (this.el.hasClass('fade')) {
10867 this.el.setXY([0,0]);
10868 this.el.removeClass('in');
10875 Roo.bootstrap.Popover.alignment = {
10876 'left' : ['r-l', [-10,0], 'right'],
10877 'right' : ['l-r', [10,0], 'left'],
10878 'bottom' : ['t-b', [0,10], 'top'],
10879 'top' : [ 'b-t', [0,-10], 'bottom']
10890 * @class Roo.bootstrap.Progress
10891 * @extends Roo.bootstrap.Component
10892 * Bootstrap Progress class
10893 * @cfg {Boolean} striped striped of the progress bar
10894 * @cfg {Boolean} active animated of the progress bar
10898 * Create a new Progress
10899 * @param {Object} config The config object
10902 Roo.bootstrap.Progress = function(config){
10903 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
10906 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
10911 getAutoCreate : function(){
10919 cfg.cls += ' progress-striped';
10923 cfg.cls += ' active';
10942 * @class Roo.bootstrap.ProgressBar
10943 * @extends Roo.bootstrap.Component
10944 * Bootstrap ProgressBar class
10945 * @cfg {Number} aria_valuenow aria-value now
10946 * @cfg {Number} aria_valuemin aria-value min
10947 * @cfg {Number} aria_valuemax aria-value max
10948 * @cfg {String} label label for the progress bar
10949 * @cfg {String} panel (success | info | warning | danger )
10950 * @cfg {String} role role of the progress bar
10951 * @cfg {String} sr_only text
10955 * Create a new ProgressBar
10956 * @param {Object} config The config object
10959 Roo.bootstrap.ProgressBar = function(config){
10960 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
10963 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
10967 aria_valuemax : 100,
10973 getAutoCreate : function()
10978 cls: 'progress-bar',
10979 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
10991 cfg.role = this.role;
10994 if(this.aria_valuenow){
10995 cfg['aria-valuenow'] = this.aria_valuenow;
10998 if(this.aria_valuemin){
10999 cfg['aria-valuemin'] = this.aria_valuemin;
11002 if(this.aria_valuemax){
11003 cfg['aria-valuemax'] = this.aria_valuemax;
11006 if(this.label && !this.sr_only){
11007 cfg.html = this.label;
11011 cfg.cls += ' progress-bar-' + this.panel;
11017 update : function(aria_valuenow)
11019 this.aria_valuenow = aria_valuenow;
11021 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
11036 * @class Roo.bootstrap.TabPanel
11037 * @extends Roo.bootstrap.Component
11038 * Bootstrap TabPanel class
11039 * @cfg {Boolean} active panel active
11040 * @cfg {String} html panel content
11041 * @cfg {String} tabId tab relate id
11042 * @cfg {String} navId The navbar which triggers show hide
11046 * Create a new TabPanel
11047 * @param {Object} config The config object
11050 Roo.bootstrap.TabPanel = function(config){
11051 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
11054 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
11061 getAutoCreate : function(){
11065 html: this.html || ''
11069 cfg.cls += ' active';
11073 cfg.tabId = this.tabId;
11078 onRender : function(ct, position)
11080 // Roo.log("Call onRender: " + this.xtype);
11082 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
11084 if (this.navId && this.tabId) {
11085 var item = Roo.bootstrap.NavGroup.get(this.navId).getNavItem(this.tabId);
11087 Roo.log("could not find navID:" + this.navId + ", tabId: " + this.tabId);
11089 item.on('changed', function(item, state) {
11090 this.setActive(state);
11096 setActive: function(state)
11098 Roo.log("panel - set active " + this.tabId + "=" + state);
11100 this.active = state;
11102 this.el.removeClass('active');
11104 } else if (!this.el.hasClass('active')) {
11105 this.el.addClass('active');
11107 this.fireEvent('changed', this, state);
11124 * @class Roo.bootstrap.DateField
11125 * @extends Roo.bootstrap.Input
11126 * Bootstrap DateField class
11127 * @cfg {Number} weekStart default 0
11128 * @cfg {Number} weekStart default 0
11129 * @cfg {Number} viewMode default empty, (months|years)
11130 * @cfg {Number} minViewMode default empty, (months|years)
11131 * @cfg {Number} startDate default -Infinity
11132 * @cfg {Number} endDate default Infinity
11133 * @cfg {Boolean} todayHighlight default false
11134 * @cfg {Boolean} todayBtn default false
11135 * @cfg {Boolean} calendarWeeks default false
11136 * @cfg {Object} daysOfWeekDisabled default empty
11138 * @cfg {Boolean} keyboardNavigation default true
11139 * @cfg {String} language default en
11142 * Create a new DateField
11143 * @param {Object} config The config object
11146 Roo.bootstrap.DateField = function(config){
11147 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
11151 * Fires when this field show.
11152 * @param {Roo.bootstrap.DateField} this
11153 * @param {Mixed} date The date value
11158 * Fires when this field hide.
11159 * @param {Roo.bootstrap.DateField} this
11160 * @param {Mixed} date The date value
11165 * Fires when select a date.
11166 * @param {Roo.bootstrap.DateField} this
11167 * @param {Mixed} date The date value
11173 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
11176 * @cfg {String} format
11177 * The default date format string which can be overriden for localization support. The format must be
11178 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
11182 * @cfg {String} altFormats
11183 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
11184 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
11186 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
11194 todayHighlight : false,
11200 keyboardNavigation: true,
11202 calendarWeeks: false,
11204 startDate: -Infinity,
11208 daysOfWeekDisabled: [],
11212 UTCDate: function()
11214 return new Date(Date.UTC.apply(Date, arguments));
11217 UTCToday: function()
11219 var today = new Date();
11220 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
11223 getDate: function() {
11224 var d = this.getUTCDate();
11225 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
11228 getUTCDate: function() {
11232 setDate: function(d) {
11233 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
11236 setUTCDate: function(d) {
11238 this.setValue(this.formatDate(this.date));
11241 onRender: function(ct, position)
11244 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
11246 this.language = this.language || 'en';
11247 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
11248 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
11250 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
11251 this.format = this.format || 'm/d/y';
11252 this.isInline = false;
11253 this.isInput = true;
11254 this.component = this.el.select('.add-on', true).first() || false;
11255 this.component = (this.component && this.component.length === 0) ? false : this.component;
11256 this.hasInput = this.component && this.inputEL().length;
11258 if (typeof(this.minViewMode === 'string')) {
11259 switch (this.minViewMode) {
11261 this.minViewMode = 1;
11264 this.minViewMode = 2;
11267 this.minViewMode = 0;
11272 if (typeof(this.viewMode === 'string')) {
11273 switch (this.viewMode) {
11286 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
11288 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
11290 this.picker().on('mousedown', this.onMousedown, this);
11291 this.picker().on('click', this.onClick, this);
11293 this.picker().addClass('datepicker-dropdown');
11295 this.startViewMode = this.viewMode;
11298 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
11299 if(!this.calendarWeeks){
11304 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
11305 v.attr('colspan', function(i, val){
11306 return parseInt(val) + 1;
11311 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
11313 this.setStartDate(this.startDate);
11314 this.setEndDate(this.endDate);
11316 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
11323 if(this.isInline) {
11328 picker : function()
11330 return this.el.select('.datepicker', true).first();
11333 fillDow: function()
11335 var dowCnt = this.weekStart;
11344 if(this.calendarWeeks){
11352 while (dowCnt < this.weekStart + 7) {
11356 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
11360 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
11363 fillMonths: function()
11366 var months = this.picker().select('>.datepicker-months td', true).first();
11368 months.dom.innerHTML = '';
11374 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
11377 months.createChild(month);
11382 update: function(){
11384 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
11386 if (this.date < this.startDate) {
11387 this.viewDate = new Date(this.startDate);
11388 } else if (this.date > this.endDate) {
11389 this.viewDate = new Date(this.endDate);
11391 this.viewDate = new Date(this.date);
11398 var d = new Date(this.viewDate),
11399 year = d.getUTCFullYear(),
11400 month = d.getUTCMonth(),
11401 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
11402 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
11403 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
11404 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
11405 currentDate = this.date && this.date.valueOf(),
11406 today = this.UTCToday();
11408 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
11410 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
11412 // this.picker.select('>tfoot th.today').
11413 // .text(dates[this.language].today)
11414 // .toggle(this.todayBtn !== false);
11416 this.updateNavArrows();
11419 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
11421 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
11423 prevMonth.setUTCDate(day);
11425 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
11427 var nextMonth = new Date(prevMonth);
11429 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
11431 nextMonth = nextMonth.valueOf();
11433 var fillMonths = false;
11435 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
11437 while(prevMonth.valueOf() < nextMonth) {
11440 if (prevMonth.getUTCDay() === this.weekStart) {
11442 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
11450 if(this.calendarWeeks){
11451 // ISO 8601: First week contains first thursday.
11452 // ISO also states week starts on Monday, but we can be more abstract here.
11454 // Start of current week: based on weekstart/current date
11455 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
11456 // Thursday of this week
11457 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
11458 // First Thursday of year, year from thursday
11459 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
11460 // Calendar week: ms between thursdays, div ms per day, div 7 days
11461 calWeek = (th - yth) / 864e5 / 7 + 1;
11463 fillMonths.cn.push({
11471 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
11473 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
11476 if (this.todayHighlight &&
11477 prevMonth.getUTCFullYear() == today.getFullYear() &&
11478 prevMonth.getUTCMonth() == today.getMonth() &&
11479 prevMonth.getUTCDate() == today.getDate()) {
11480 clsName += ' today';
11483 if (currentDate && prevMonth.valueOf() === currentDate) {
11484 clsName += ' active';
11487 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
11488 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
11489 clsName += ' disabled';
11492 fillMonths.cn.push({
11494 cls: 'day ' + clsName,
11495 html: prevMonth.getDate()
11498 prevMonth.setDate(prevMonth.getDate()+1);
11501 var currentYear = this.date && this.date.getUTCFullYear();
11502 var currentMonth = this.date && this.date.getUTCMonth();
11504 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
11506 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
11507 v.removeClass('active');
11509 if(currentYear === year && k === currentMonth){
11510 v.addClass('active');
11513 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
11514 v.addClass('disabled');
11520 year = parseInt(year/10, 10) * 10;
11522 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
11524 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
11527 for (var i = -1; i < 11; i++) {
11528 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
11530 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
11538 showMode: function(dir) {
11540 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
11542 Roo.each(this.picker().select('>div',true).elements, function(v){
11543 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
11546 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
11551 if(this.isInline) return;
11553 this.picker().removeClass(['bottom', 'top']);
11555 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
11557 * place to the top of element!
11561 this.picker().addClass('top');
11562 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
11567 this.picker().addClass('bottom');
11569 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
11572 parseDate : function(value){
11573 if(!value || value instanceof Date){
11576 var v = Date.parseDate(value, this.format);
11577 if (!v && this.useIso) {
11578 v = Date.parseDate(value, 'Y-m-d');
11580 if(!v && this.altFormats){
11581 if(!this.altFormatsArray){
11582 this.altFormatsArray = this.altFormats.split("|");
11584 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
11585 v = Date.parseDate(value, this.altFormatsArray[i]);
11591 formatDate : function(date, fmt){
11592 return (!date || !(date instanceof Date)) ?
11593 date : date.dateFormat(fmt || this.format);
11596 onFocus : function()
11598 Roo.bootstrap.DateField.superclass.onFocus.call(this);
11602 onBlur : function()
11604 Roo.bootstrap.DateField.superclass.onBlur.call(this);
11610 this.picker().show();
11614 this.fireEvent('show', this, this.date);
11619 if(this.isInline) return;
11620 this.picker().hide();
11621 this.viewMode = this.startViewMode;
11624 this.fireEvent('hide', this, this.date);
11628 onMousedown: function(e){
11629 e.stopPropagation();
11630 e.preventDefault();
11633 keyup: function(e){
11634 Roo.bootstrap.DateField.superclass.keyup.call(this);
11639 setValue: function(v){
11640 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
11642 this.fireEvent('select', this, this.date);
11646 fireKey: function(e){
11647 if (!this.picker().isVisible()){
11648 if (e.keyCode == 27) // allow escape to hide and re-show picker
11652 var dateChanged = false,
11654 newDate, newViewDate;
11658 e.preventDefault();
11662 if (!this.keyboardNavigation) break;
11663 dir = e.keyCode == 37 ? -1 : 1;
11666 newDate = this.moveYear(this.date, dir);
11667 newViewDate = this.moveYear(this.viewDate, dir);
11668 } else if (e.shiftKey){
11669 newDate = this.moveMonth(this.date, dir);
11670 newViewDate = this.moveMonth(this.viewDate, dir);
11672 newDate = new Date(this.date);
11673 newDate.setUTCDate(this.date.getUTCDate() + dir);
11674 newViewDate = new Date(this.viewDate);
11675 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
11677 if (this.dateWithinRange(newDate)){
11678 this.date = newDate;
11679 this.viewDate = newViewDate;
11680 this.setValue(this.formatDate(this.date));
11682 e.preventDefault();
11683 dateChanged = true;
11688 if (!this.keyboardNavigation) break;
11689 dir = e.keyCode == 38 ? -1 : 1;
11691 newDate = this.moveYear(this.date, dir);
11692 newViewDate = this.moveYear(this.viewDate, dir);
11693 } else if (e.shiftKey){
11694 newDate = this.moveMonth(this.date, dir);
11695 newViewDate = this.moveMonth(this.viewDate, dir);
11697 newDate = new Date(this.date);
11698 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
11699 newViewDate = new Date(this.viewDate);
11700 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
11702 if (this.dateWithinRange(newDate)){
11703 this.date = newDate;
11704 this.viewDate = newViewDate;
11705 this.setValue(this.formatDate(this.date));
11707 e.preventDefault();
11708 dateChanged = true;
11712 this.setValue(this.formatDate(this.date));
11714 e.preventDefault();
11717 this.setValue(this.formatDate(this.date));
11724 onClick: function(e) {
11725 e.stopPropagation();
11726 e.preventDefault();
11728 var target = e.getTarget();
11730 if(target.nodeName.toLowerCase() === 'i'){
11731 target = Roo.get(target).dom.parentNode;
11734 var nodeName = target.nodeName;
11735 var className = target.className;
11736 var html = target.innerHTML;
11738 switch(nodeName.toLowerCase()) {
11740 switch(className) {
11746 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
11747 switch(this.viewMode){
11749 this.viewDate = this.moveMonth(this.viewDate, dir);
11753 this.viewDate = this.moveYear(this.viewDate, dir);
11759 var date = new Date();
11760 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
11762 this.setValue(this.formatDate(this.date));
11768 if (className.indexOf('disabled') === -1) {
11769 this.viewDate.setUTCDate(1);
11770 if (className.indexOf('month') !== -1) {
11771 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
11773 var year = parseInt(html, 10) || 0;
11774 this.viewDate.setUTCFullYear(year);
11783 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
11784 var day = parseInt(html, 10) || 1;
11785 var year = this.viewDate.getUTCFullYear(),
11786 month = this.viewDate.getUTCMonth();
11788 if (className.indexOf('old') !== -1) {
11795 } else if (className.indexOf('new') !== -1) {
11803 this.date = this.UTCDate(year, month, day,0,0,0,0);
11804 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
11806 this.setValue(this.formatDate(this.date));
11813 setStartDate: function(startDate){
11814 this.startDate = startDate || -Infinity;
11815 if (this.startDate !== -Infinity) {
11816 this.startDate = this.parseDate(this.startDate);
11819 this.updateNavArrows();
11822 setEndDate: function(endDate){
11823 this.endDate = endDate || Infinity;
11824 if (this.endDate !== Infinity) {
11825 this.endDate = this.parseDate(this.endDate);
11828 this.updateNavArrows();
11831 setDaysOfWeekDisabled: function(daysOfWeekDisabled){
11832 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
11833 if (typeof(this.daysOfWeekDisabled) !== 'object') {
11834 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
11836 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
11837 return parseInt(d, 10);
11840 this.updateNavArrows();
11843 updateNavArrows: function() {
11844 var d = new Date(this.viewDate),
11845 year = d.getUTCFullYear(),
11846 month = d.getUTCMonth();
11848 Roo.each(this.picker().select('.prev', true).elements, function(v){
11850 switch (this.viewMode) {
11853 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
11859 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
11866 Roo.each(this.picker().select('.next', true).elements, function(v){
11868 switch (this.viewMode) {
11871 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
11877 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
11885 moveMonth: function(date, dir){
11886 if (!dir) return date;
11887 var new_date = new Date(date.valueOf()),
11888 day = new_date.getUTCDate(),
11889 month = new_date.getUTCMonth(),
11890 mag = Math.abs(dir),
11892 dir = dir > 0 ? 1 : -1;
11895 // If going back one month, make sure month is not current month
11896 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
11898 return new_date.getUTCMonth() == month;
11900 // If going forward one month, make sure month is as expected
11901 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
11903 return new_date.getUTCMonth() != new_month;
11905 new_month = month + dir;
11906 new_date.setUTCMonth(new_month);
11907 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
11908 if (new_month < 0 || new_month > 11)
11909 new_month = (new_month + 12) % 12;
11911 // For magnitudes >1, move one month at a time...
11912 for (var i=0; i<mag; i++)
11913 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
11914 new_date = this.moveMonth(new_date, dir);
11915 // ...then reset the day, keeping it in the new month
11916 new_month = new_date.getUTCMonth();
11917 new_date.setUTCDate(day);
11919 return new_month != new_date.getUTCMonth();
11922 // Common date-resetting loop -- if date is beyond end of month, make it
11925 new_date.setUTCDate(--day);
11926 new_date.setUTCMonth(new_month);
11931 moveYear: function(date, dir){
11932 return this.moveMonth(date, dir*12);
11935 dateWithinRange: function(date){
11936 return date >= this.startDate && date <= this.endDate;
11940 remove: function() {
11941 this.picker().remove();
11946 Roo.apply(Roo.bootstrap.DateField, {
11957 html: '<i class="icon-arrow-left"/>'
11967 html: '<i class="icon-arrow-right"/>'
12009 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
12010 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
12011 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
12012 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
12013 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
12026 navFnc: 'FullYear',
12031 navFnc: 'FullYear',
12036 Roo.apply(Roo.bootstrap.DateField, {
12040 cls: 'datepicker dropdown-menu',
12044 cls: 'datepicker-days',
12048 cls: 'table-condensed',
12050 Roo.bootstrap.DateField.head,
12054 Roo.bootstrap.DateField.footer
12061 cls: 'datepicker-months',
12065 cls: 'table-condensed',
12067 Roo.bootstrap.DateField.head,
12068 Roo.bootstrap.DateField.content,
12069 Roo.bootstrap.DateField.footer
12076 cls: 'datepicker-years',
12080 cls: 'table-condensed',
12082 Roo.bootstrap.DateField.head,
12083 Roo.bootstrap.DateField.content,
12084 Roo.bootstrap.DateField.footer
12103 * @class Roo.bootstrap.TimeField
12104 * @extends Roo.bootstrap.Input
12105 * Bootstrap DateField class
12109 * Create a new TimeField
12110 * @param {Object} config The config object
12113 Roo.bootstrap.TimeField = function(config){
12114 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
12118 * Fires when this field show.
12119 * @param {Roo.bootstrap.DateField} this
12120 * @param {Mixed} date The date value
12125 * Fires when this field hide.
12126 * @param {Roo.bootstrap.DateField} this
12127 * @param {Mixed} date The date value
12132 * Fires when select a date.
12133 * @param {Roo.bootstrap.DateField} this
12134 * @param {Mixed} date The date value
12140 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
12143 * @cfg {String} format
12144 * The default time format string which can be overriden for localization support. The format must be
12145 * valid according to {@link Date#parseDate} (defaults to 'H:i').
12149 onRender: function(ct, position)
12152 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
12154 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
12156 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12158 this.pop = this.picker().select('>.datepicker-time',true).first();
12159 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
12161 this.picker().on('mousedown', this.onMousedown, this);
12162 this.picker().on('click', this.onClick, this);
12164 this.picker().addClass('datepicker-dropdown');
12169 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
12170 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
12171 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
12172 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
12173 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
12174 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
12178 fireKey: function(e){
12179 if (!this.picker().isVisible()){
12180 if (e.keyCode == 27) // allow escape to hide and re-show picker
12185 e.preventDefault();
12193 this.onTogglePeriod();
12196 this.onIncrementMinutes();
12199 this.onDecrementMinutes();
12208 onClick: function(e) {
12209 e.stopPropagation();
12210 e.preventDefault();
12213 picker : function()
12215 return this.el.select('.datepicker', true).first();
12218 fillTime: function()
12220 var time = this.pop.select('tbody', true).first();
12222 time.dom.innerHTML = '';
12237 cls: 'hours-up glyphicon glyphicon-chevron-up'
12257 cls: 'minutes-up glyphicon glyphicon-chevron-up'
12278 cls: 'timepicker-hour',
12293 cls: 'timepicker-minute',
12308 cls: 'btn btn-primary period',
12330 cls: 'hours-down glyphicon glyphicon-chevron-down'
12350 cls: 'minutes-down glyphicon glyphicon-chevron-down'
12368 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
12375 var hours = this.time.getHours();
12376 var minutes = this.time.getMinutes();
12389 hours = hours - 12;
12393 hours = '0' + hours;
12397 minutes = '0' + minutes;
12400 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
12401 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
12402 this.pop.select('button', true).first().dom.innerHTML = period;
12408 this.picker().removeClass(['bottom', 'top']);
12410 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
12412 * place to the top of element!
12416 this.picker().addClass('top');
12417 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12422 this.picker().addClass('bottom');
12424 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12427 onFocus : function()
12429 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
12433 onBlur : function()
12435 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
12441 this.picker().show();
12446 this.fireEvent('show', this, this.date);
12451 this.picker().hide();
12454 this.fireEvent('hide', this, this.date);
12457 setTime : function()
12460 this.setValue(this.time.format(this.format));
12462 this.fireEvent('select', this, this.date);
12467 onMousedown: function(e){
12468 e.stopPropagation();
12469 e.preventDefault();
12472 onIncrementHours: function()
12474 Roo.log('onIncrementHours');
12475 this.time = this.time.add(Date.HOUR, 1);
12480 onDecrementHours: function()
12482 Roo.log('onDecrementHours');
12483 this.time = this.time.add(Date.HOUR, -1);
12487 onIncrementMinutes: function()
12489 Roo.log('onIncrementMinutes');
12490 this.time = this.time.add(Date.MINUTE, 1);
12494 onDecrementMinutes: function()
12496 Roo.log('onDecrementMinutes');
12497 this.time = this.time.add(Date.MINUTE, -1);
12501 onTogglePeriod: function()
12503 Roo.log('onTogglePeriod');
12504 this.time = this.time.add(Date.HOUR, 12);
12511 Roo.apply(Roo.bootstrap.TimeField, {
12541 cls: 'btn btn-info ok',
12553 Roo.apply(Roo.bootstrap.TimeField, {
12557 cls: 'datepicker dropdown-menu',
12561 cls: 'datepicker-time',
12565 cls: 'table-condensed',
12567 Roo.bootstrap.TimeField.content,
12568 Roo.bootstrap.TimeField.footer
12587 * @class Roo.bootstrap.CheckBox
12588 * @extends Roo.bootstrap.Input
12589 * Bootstrap CheckBox class
12591 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
12592 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
12593 * @cfg {String} boxLabel The text that appears beside the checkbox
12594 * @cfg {Boolean} checked initnal the element
12597 * Create a new CheckBox
12598 * @param {Object} config The config object
12601 Roo.bootstrap.CheckBox = function(config){
12602 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
12607 * Fires when the element is checked or unchecked.
12608 * @param {Roo.bootstrap.CheckBox} this This input
12609 * @param {Boolean} checked The new checked value
12615 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
12617 inputType: 'checkbox',
12623 getAutoCreate : function()
12625 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
12631 cfg.cls = 'form-group' //input-group
12636 type : this.inputType,
12637 value : (!this.checked) ? this.valueOff : this.inputValue,
12639 placeholder : this.placeholder || ''
12643 if (this.disabled) {
12644 input.disabled=true;
12648 input.checked = this.checked;
12652 input.name = this.name;
12656 input.cls += ' input-' + this.size;
12660 ['xs','sm','md','lg'].map(function(size){
12661 if (settings[size]) {
12662 cfg.cls += ' col-' + size + '-' + settings[size];
12666 var inputblock = input;
12668 if (this.before || this.after) {
12671 cls : 'input-group',
12675 inputblock.cn.push({
12677 cls : 'input-group-addon',
12681 inputblock.cn.push(input);
12683 inputblock.cn.push({
12685 cls : 'input-group-addon',
12692 if (align ==='left' && this.fieldLabel.length) {
12693 Roo.log("left and has label");
12699 cls : 'control-label col-md-' + this.labelWidth,
12700 html : this.fieldLabel
12704 cls : "col-md-" + (12 - this.labelWidth),
12711 } else if ( this.fieldLabel.length) {
12716 tag: this.boxLabel ? 'span' : 'label',
12718 cls: 'control-label box-input-label',
12719 //cls : 'input-group-addon',
12720 html : this.fieldLabel
12730 Roo.log(" no label && no align");
12745 html: this.boxLabel
12754 * return the real input element.
12756 inputEl: function ()
12758 return this.el.select('input.form-box',true).first();
12761 initEvents : function()
12763 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
12765 this.inputEl().on('click', this.onClick, this);
12769 onClick : function()
12771 this.setChecked(!this.checked);
12774 setChecked : function(state,suppressEvent)
12776 this.checked = state;
12778 this.inputEl().dom.checked = state;
12780 if(suppressEvent !== true){
12781 this.fireEvent('check', this, state);
12784 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
12788 setValue : function(v,suppressEvent)
12790 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
12804 * @class Roo.bootstrap.Radio
12805 * @extends Roo.bootstrap.CheckBox
12806 * Bootstrap Radio class
12809 * Create a new Radio
12810 * @param {Object} config The config object
12813 Roo.bootstrap.Radio = function(config){
12814 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
12818 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
12820 inputType: 'radio',
12824 getAutoCreate : function()
12826 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
12832 cfg.cls = 'form-group' //input-group
12837 type : this.inputType,
12838 value : (!this.checked) ? this.valueOff : this.inputValue,
12840 placeholder : this.placeholder || ''
12844 if (this.disabled) {
12845 input.disabled=true;
12849 input.checked = this.checked;
12853 input.name = this.name;
12857 input.cls += ' input-' + this.size;
12861 ['xs','sm','md','lg'].map(function(size){
12862 if (settings[size]) {
12863 cfg.cls += ' col-' + size + '-' + settings[size];
12867 var inputblock = input;
12869 if (this.before || this.after) {
12872 cls : 'input-group',
12876 inputblock.cn.push({
12878 cls : 'input-group-addon',
12882 inputblock.cn.push(input);
12884 inputblock.cn.push({
12886 cls : 'input-group-addon',
12893 if (align ==='left' && this.fieldLabel.length) {
12894 Roo.log("left and has label");
12900 cls : 'control-label col-md-' + this.labelWidth,
12901 html : this.fieldLabel
12905 cls : "col-md-" + (12 - this.labelWidth),
12912 } else if ( this.fieldLabel.length) {
12919 cls: 'control-label box-input-label',
12920 //cls : 'input-group-addon',
12921 html : this.fieldLabel
12931 Roo.log(" no label && no align");
12946 html: this.boxLabel
12954 onClick : function()
12956 this.setChecked(true);
12959 setChecked : function(state,suppressEvent)
12962 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
12963 v.dom.checked = false;
12967 this.checked = state;
12968 this.inputEl().dom.checked = state;
12970 if(suppressEvent !== true){
12971 this.fireEvent('check', this, state);
12974 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
12978 getGroupValue : function()
12981 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
12982 if(v.dom.checked == true){
12983 value = v.dom.value;
12991 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
12992 * @return {Mixed} value The field value
12994 getValue : function(){
12995 return this.getGroupValue();
13001 //<script type="text/javascript">
13004 * Based Ext JS Library 1.1.1
13005 * Copyright(c) 2006-2007, Ext JS, LLC.
13011 * @class Roo.HtmlEditorCore
13012 * @extends Roo.Component
13013 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
13015 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
13018 Roo.HtmlEditorCore = function(config){
13021 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
13024 * @event initialize
13025 * Fires when the editor is fully initialized (including the iframe)
13026 * @param {Roo.HtmlEditorCore} this
13031 * Fires when the editor is first receives the focus. Any insertion must wait
13032 * until after this event.
13033 * @param {Roo.HtmlEditorCore} this
13037 * @event beforesync
13038 * Fires before the textarea is updated with content from the editor iframe. Return false
13039 * to cancel the sync.
13040 * @param {Roo.HtmlEditorCore} this
13041 * @param {String} html
13045 * @event beforepush
13046 * Fires before the iframe editor is updated with content from the textarea. Return false
13047 * to cancel the push.
13048 * @param {Roo.HtmlEditorCore} this
13049 * @param {String} html
13054 * Fires when the textarea is updated with content from the editor iframe.
13055 * @param {Roo.HtmlEditorCore} this
13056 * @param {String} html
13061 * Fires when the iframe editor is updated with content from the textarea.
13062 * @param {Roo.HtmlEditorCore} this
13063 * @param {String} html
13068 * @event editorevent
13069 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
13070 * @param {Roo.HtmlEditorCore} this
13078 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
13082 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
13088 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
13093 * @cfg {Number} height (in pixels)
13097 * @cfg {Number} width (in pixels)
13102 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
13105 stylesheets: false,
13110 // private properties
13111 validationEvent : false,
13113 initialized : false,
13115 sourceEditMode : false,
13116 onFocus : Roo.emptyFn,
13118 hideMode:'offsets',
13126 * Protected method that will not generally be called directly. It
13127 * is called when the editor initializes the iframe with HTML contents. Override this method if you
13128 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
13130 getDocMarkup : function(){
13133 Roo.log(this.stylesheets);
13135 // inherit styels from page...??
13136 if (this.stylesheets === false) {
13138 Roo.get(document.head).select('style').each(function(node) {
13139 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
13142 Roo.get(document.head).select('link').each(function(node) {
13143 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
13146 } else if (!this.stylesheets.length) {
13148 st = '<style type="text/css">' +
13149 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
13152 Roo.each(this.stylesheets, function(s) {
13153 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
13158 st += '<style type="text/css">' +
13159 'IMG { cursor: pointer } ' +
13163 return '<html><head>' + st +
13164 //<style type="text/css">' +
13165 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
13167 ' </head><body class="roo-htmleditor-body"></body></html>';
13171 onRender : function(ct, position)
13174 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
13175 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
13178 this.el.dom.style.border = '0 none';
13179 this.el.dom.setAttribute('tabIndex', -1);
13180 this.el.addClass('x-hidden hide');
13184 if(Roo.isIE){ // fix IE 1px bogus margin
13185 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
13189 this.frameId = Roo.id();
13193 var iframe = this.owner.wrap.createChild({
13195 cls: 'form-control', // bootstrap..
13197 name: this.frameId,
13198 frameBorder : 'no',
13199 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
13204 this.iframe = iframe.dom;
13206 this.assignDocWin();
13208 this.doc.designMode = 'on';
13211 this.doc.write(this.getDocMarkup());
13215 var task = { // must defer to wait for browser to be ready
13217 //console.log("run task?" + this.doc.readyState);
13218 this.assignDocWin();
13219 if(this.doc.body || this.doc.readyState == 'complete'){
13221 this.doc.designMode="on";
13225 Roo.TaskMgr.stop(task);
13226 this.initEditor.defer(10, this);
13233 Roo.TaskMgr.start(task);
13240 onResize : function(w, h)
13242 Roo.log('resize: ' +w + ',' + h );
13243 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
13247 if(typeof w == 'number'){
13249 this.iframe.style.width = w + 'px';
13251 if(typeof h == 'number'){
13253 this.iframe.style.height = h + 'px';
13255 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
13262 * Toggles the editor between standard and source edit mode.
13263 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
13265 toggleSourceEdit : function(sourceEditMode){
13267 this.sourceEditMode = sourceEditMode === true;
13269 if(this.sourceEditMode){
13271 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
13274 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
13275 //this.iframe.className = '';
13278 //this.setSize(this.owner.wrap.getSize());
13279 //this.fireEvent('editmodechange', this, this.sourceEditMode);
13286 * Protected method that will not generally be called directly. If you need/want
13287 * custom HTML cleanup, this is the method you should override.
13288 * @param {String} html The HTML to be cleaned
13289 * return {String} The cleaned HTML
13291 cleanHtml : function(html){
13292 html = String(html);
13293 if(html.length > 5){
13294 if(Roo.isSafari){ // strip safari nonsense
13295 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
13298 if(html == ' '){
13305 * HTML Editor -> Textarea
13306 * Protected method that will not generally be called directly. Syncs the contents
13307 * of the editor iframe with the textarea.
13309 syncValue : function(){
13310 if(this.initialized){
13311 var bd = (this.doc.body || this.doc.documentElement);
13312 //this.cleanUpPaste(); -- this is done else where and causes havoc..
13313 var html = bd.innerHTML;
13315 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
13316 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
13318 html = '<div style="'+m[0]+'">' + html + '</div>';
13321 html = this.cleanHtml(html);
13322 // fix up the special chars.. normaly like back quotes in word...
13323 // however we do not want to do this with chinese..
13324 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
13325 var cc = b.charCodeAt();
13327 (cc >= 0x4E00 && cc < 0xA000 ) ||
13328 (cc >= 0x3400 && cc < 0x4E00 ) ||
13329 (cc >= 0xf900 && cc < 0xfb00 )
13335 if(this.owner.fireEvent('beforesync', this, html) !== false){
13336 this.el.dom.value = html;
13337 this.owner.fireEvent('sync', this, html);
13343 * Protected method that will not generally be called directly. Pushes the value of the textarea
13344 * into the iframe editor.
13346 pushValue : function(){
13347 if(this.initialized){
13348 var v = this.el.dom.value.trim();
13350 // if(v.length < 1){
13354 if(this.owner.fireEvent('beforepush', this, v) !== false){
13355 var d = (this.doc.body || this.doc.documentElement);
13357 this.cleanUpPaste();
13358 this.el.dom.value = d.innerHTML;
13359 this.owner.fireEvent('push', this, v);
13365 deferFocus : function(){
13366 this.focus.defer(10, this);
13370 focus : function(){
13371 if(this.win && !this.sourceEditMode){
13378 assignDocWin: function()
13380 var iframe = this.iframe;
13383 this.doc = iframe.contentWindow.document;
13384 this.win = iframe.contentWindow;
13386 if (!Roo.get(this.frameId)) {
13389 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
13390 this.win = Roo.get(this.frameId).dom.contentWindow;
13395 initEditor : function(){
13396 //console.log("INIT EDITOR");
13397 this.assignDocWin();
13401 this.doc.designMode="on";
13403 this.doc.write(this.getDocMarkup());
13406 var dbody = (this.doc.body || this.doc.documentElement);
13407 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
13408 // this copies styles from the containing element into thsi one..
13409 // not sure why we need all of this..
13410 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
13411 ss['background-attachment'] = 'fixed'; // w3c
13412 dbody.bgProperties = 'fixed'; // ie
13413 Roo.DomHelper.applyStyles(dbody, ss);
13414 Roo.EventManager.on(this.doc, {
13415 //'mousedown': this.onEditorEvent,
13416 'mouseup': this.onEditorEvent,
13417 'dblclick': this.onEditorEvent,
13418 'click': this.onEditorEvent,
13419 'keyup': this.onEditorEvent,
13424 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
13426 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
13427 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
13429 this.initialized = true;
13431 this.owner.fireEvent('initialize', this);
13436 onDestroy : function(){
13442 //for (var i =0; i < this.toolbars.length;i++) {
13443 // // fixme - ask toolbars for heights?
13444 // this.toolbars[i].onDestroy();
13447 //this.wrap.dom.innerHTML = '';
13448 //this.wrap.remove();
13453 onFirstFocus : function(){
13455 this.assignDocWin();
13458 this.activated = true;
13461 if(Roo.isGecko){ // prevent silly gecko errors
13463 var s = this.win.getSelection();
13464 if(!s.focusNode || s.focusNode.nodeType != 3){
13465 var r = s.getRangeAt(0);
13466 r.selectNodeContents((this.doc.body || this.doc.documentElement));
13471 this.execCmd('useCSS', true);
13472 this.execCmd('styleWithCSS', false);
13475 this.owner.fireEvent('activate', this);
13479 adjustFont: function(btn){
13480 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
13481 //if(Roo.isSafari){ // safari
13484 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
13485 if(Roo.isSafari){ // safari
13486 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
13487 v = (v < 10) ? 10 : v;
13488 v = (v > 48) ? 48 : v;
13489 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
13494 v = Math.max(1, v+adjust);
13496 this.execCmd('FontSize', v );
13499 onEditorEvent : function(e){
13500 this.owner.fireEvent('editorevent', this, e);
13501 // this.updateToolbar();
13502 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
13505 insertTag : function(tg)
13507 // could be a bit smarter... -> wrap the current selected tRoo..
13508 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
13510 range = this.createRange(this.getSelection());
13511 var wrappingNode = this.doc.createElement(tg.toLowerCase());
13512 wrappingNode.appendChild(range.extractContents());
13513 range.insertNode(wrappingNode);
13520 this.execCmd("formatblock", tg);
13524 insertText : function(txt)
13528 var range = this.createRange();
13529 range.deleteContents();
13530 //alert(Sender.getAttribute('label'));
13532 range.insertNode(this.doc.createTextNode(txt));
13538 * Executes a Midas editor command on the editor document and performs necessary focus and
13539 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
13540 * @param {String} cmd The Midas command
13541 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
13543 relayCmd : function(cmd, value){
13545 this.execCmd(cmd, value);
13546 this.owner.fireEvent('editorevent', this);
13547 //this.updateToolbar();
13548 this.owner.deferFocus();
13552 * Executes a Midas editor command directly on the editor document.
13553 * For visual commands, you should use {@link #relayCmd} instead.
13554 * <b>This should only be called after the editor is initialized.</b>
13555 * @param {String} cmd The Midas command
13556 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
13558 execCmd : function(cmd, value){
13559 this.doc.execCommand(cmd, false, value === undefined ? null : value);
13566 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
13568 * @param {String} text | dom node..
13570 insertAtCursor : function(text)
13575 if(!this.activated){
13581 var r = this.doc.selection.createRange();
13592 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
13596 // from jquery ui (MIT licenced)
13598 var win = this.win;
13600 if (win.getSelection && win.getSelection().getRangeAt) {
13601 range = win.getSelection().getRangeAt(0);
13602 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
13603 range.insertNode(node);
13604 } else if (win.document.selection && win.document.selection.createRange) {
13605 // no firefox support
13606 var txt = typeof(text) == 'string' ? text : text.outerHTML;
13607 win.document.selection.createRange().pasteHTML(txt);
13609 // no firefox support
13610 var txt = typeof(text) == 'string' ? text : text.outerHTML;
13611 this.execCmd('InsertHTML', txt);
13620 mozKeyPress : function(e){
13622 var c = e.getCharCode(), cmd;
13625 c = String.fromCharCode(c).toLowerCase();
13639 this.cleanUpPaste.defer(100, this);
13647 e.preventDefault();
13655 fixKeys : function(){ // load time branching for fastest keydown performance
13657 return function(e){
13658 var k = e.getKey(), r;
13661 r = this.doc.selection.createRange();
13664 r.pasteHTML('    ');
13671 r = this.doc.selection.createRange();
13673 var target = r.parentElement();
13674 if(!target || target.tagName.toLowerCase() != 'li'){
13676 r.pasteHTML('<br />');
13682 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
13683 this.cleanUpPaste.defer(100, this);
13689 }else if(Roo.isOpera){
13690 return function(e){
13691 var k = e.getKey();
13695 this.execCmd('InsertHTML','    ');
13698 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
13699 this.cleanUpPaste.defer(100, this);
13704 }else if(Roo.isSafari){
13705 return function(e){
13706 var k = e.getKey();
13710 this.execCmd('InsertText','\t');
13714 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
13715 this.cleanUpPaste.defer(100, this);
13723 getAllAncestors: function()
13725 var p = this.getSelectedNode();
13728 a.push(p); // push blank onto stack..
13729 p = this.getParentElement();
13733 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
13737 a.push(this.doc.body);
13741 lastSelNode : false,
13744 getSelection : function()
13746 this.assignDocWin();
13747 return Roo.isIE ? this.doc.selection : this.win.getSelection();
13750 getSelectedNode: function()
13752 // this may only work on Gecko!!!
13754 // should we cache this!!!!
13759 var range = this.createRange(this.getSelection()).cloneRange();
13762 var parent = range.parentElement();
13764 var testRange = range.duplicate();
13765 testRange.moveToElementText(parent);
13766 if (testRange.inRange(range)) {
13769 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
13772 parent = parent.parentElement;
13777 // is ancestor a text element.
13778 var ac = range.commonAncestorContainer;
13779 if (ac.nodeType == 3) {
13780 ac = ac.parentNode;
13783 var ar = ac.childNodes;
13786 var other_nodes = [];
13787 var has_other_nodes = false;
13788 for (var i=0;i<ar.length;i++) {
13789 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
13792 // fullly contained node.
13794 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
13799 // probably selected..
13800 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
13801 other_nodes.push(ar[i]);
13805 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
13810 has_other_nodes = true;
13812 if (!nodes.length && other_nodes.length) {
13813 nodes= other_nodes;
13815 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
13821 createRange: function(sel)
13823 // this has strange effects when using with
13824 // top toolbar - not sure if it's a great idea.
13825 //this.editor.contentWindow.focus();
13826 if (typeof sel != "undefined") {
13828 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
13830 return this.doc.createRange();
13833 return this.doc.createRange();
13836 getParentElement: function()
13839 this.assignDocWin();
13840 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
13842 var range = this.createRange(sel);
13845 var p = range.commonAncestorContainer;
13846 while (p.nodeType == 3) { // text node
13857 * Range intersection.. the hard stuff...
13861 * [ -- selected range --- ]
13865 * if end is before start or hits it. fail.
13866 * if start is after end or hits it fail.
13868 * if either hits (but other is outside. - then it's not
13874 // @see http://www.thismuchiknow.co.uk/?p=64.
13875 rangeIntersectsNode : function(range, node)
13877 var nodeRange = node.ownerDocument.createRange();
13879 nodeRange.selectNode(node);
13881 nodeRange.selectNodeContents(node);
13884 var rangeStartRange = range.cloneRange();
13885 rangeStartRange.collapse(true);
13887 var rangeEndRange = range.cloneRange();
13888 rangeEndRange.collapse(false);
13890 var nodeStartRange = nodeRange.cloneRange();
13891 nodeStartRange.collapse(true);
13893 var nodeEndRange = nodeRange.cloneRange();
13894 nodeEndRange.collapse(false);
13896 return rangeStartRange.compareBoundaryPoints(
13897 Range.START_TO_START, nodeEndRange) == -1 &&
13898 rangeEndRange.compareBoundaryPoints(
13899 Range.START_TO_START, nodeStartRange) == 1;
13903 rangeCompareNode : function(range, node)
13905 var nodeRange = node.ownerDocument.createRange();
13907 nodeRange.selectNode(node);
13909 nodeRange.selectNodeContents(node);
13913 range.collapse(true);
13915 nodeRange.collapse(true);
13917 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
13918 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
13920 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
13922 var nodeIsBefore = ss == 1;
13923 var nodeIsAfter = ee == -1;
13925 if (nodeIsBefore && nodeIsAfter)
13927 if (!nodeIsBefore && nodeIsAfter)
13928 return 1; //right trailed.
13930 if (nodeIsBefore && !nodeIsAfter)
13931 return 2; // left trailed.
13936 // private? - in a new class?
13937 cleanUpPaste : function()
13939 // cleans up the whole document..
13940 Roo.log('cleanuppaste');
13942 this.cleanUpChildren(this.doc.body);
13943 var clean = this.cleanWordChars(this.doc.body.innerHTML);
13944 if (clean != this.doc.body.innerHTML) {
13945 this.doc.body.innerHTML = clean;
13950 cleanWordChars : function(input) {// change the chars to hex code
13951 var he = Roo.HtmlEditorCore;
13953 var output = input;
13954 Roo.each(he.swapCodes, function(sw) {
13955 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
13957 output = output.replace(swapper, sw[1]);
13964 cleanUpChildren : function (n)
13966 if (!n.childNodes.length) {
13969 for (var i = n.childNodes.length-1; i > -1 ; i--) {
13970 this.cleanUpChild(n.childNodes[i]);
13977 cleanUpChild : function (node)
13980 //console.log(node);
13981 if (node.nodeName == "#text") {
13982 // clean up silly Windows -- stuff?
13985 if (node.nodeName == "#comment") {
13986 node.parentNode.removeChild(node);
13987 // clean up silly Windows -- stuff?
13991 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
13993 node.parentNode.removeChild(node);
13998 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
14000 // remove <a name=....> as rendering on yahoo mailer is borked with this.
14001 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
14003 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
14004 // remove_keep_children = true;
14007 if (remove_keep_children) {
14008 this.cleanUpChildren(node);
14009 // inserts everything just before this node...
14010 while (node.childNodes.length) {
14011 var cn = node.childNodes[0];
14012 node.removeChild(cn);
14013 node.parentNode.insertBefore(cn, node);
14015 node.parentNode.removeChild(node);
14019 if (!node.attributes || !node.attributes.length) {
14020 this.cleanUpChildren(node);
14024 function cleanAttr(n,v)
14027 if (v.match(/^\./) || v.match(/^\//)) {
14030 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
14033 if (v.match(/^#/)) {
14036 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
14037 node.removeAttribute(n);
14041 function cleanStyle(n,v)
14043 if (v.match(/expression/)) { //XSS?? should we even bother..
14044 node.removeAttribute(n);
14047 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
14048 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
14051 var parts = v.split(/;/);
14054 Roo.each(parts, function(p) {
14055 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
14059 var l = p.split(':').shift().replace(/\s+/g,'');
14060 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
14062 if ( cblack.indexOf(l) > -1) {
14063 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
14064 //node.removeAttribute(n);
14068 // only allow 'c whitelisted system attributes'
14069 if ( cwhite.length && cwhite.indexOf(l) < 0) {
14070 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
14071 //node.removeAttribute(n);
14081 if (clean.length) {
14082 node.setAttribute(n, clean.join(';'));
14084 node.removeAttribute(n);
14090 for (var i = node.attributes.length-1; i > -1 ; i--) {
14091 var a = node.attributes[i];
14094 if (a.name.toLowerCase().substr(0,2)=='on') {
14095 node.removeAttribute(a.name);
14098 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
14099 node.removeAttribute(a.name);
14102 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
14103 cleanAttr(a.name,a.value); // fixme..
14106 if (a.name == 'style') {
14107 cleanStyle(a.name,a.value);
14110 /// clean up MS crap..
14111 // tecnically this should be a list of valid class'es..
14114 if (a.name == 'class') {
14115 if (a.value.match(/^Mso/)) {
14116 node.className = '';
14119 if (a.value.match(/body/)) {
14120 node.className = '';
14131 this.cleanUpChildren(node);
14137 // hide stuff that is not compatible
14151 * @event specialkey
14155 * @cfg {String} fieldClass @hide
14158 * @cfg {String} focusClass @hide
14161 * @cfg {String} autoCreate @hide
14164 * @cfg {String} inputType @hide
14167 * @cfg {String} invalidClass @hide
14170 * @cfg {String} invalidText @hide
14173 * @cfg {String} msgFx @hide
14176 * @cfg {String} validateOnBlur @hide
14180 Roo.HtmlEditorCore.white = [
14181 'area', 'br', 'img', 'input', 'hr', 'wbr',
14183 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
14184 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
14185 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
14186 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
14187 'table', 'ul', 'xmp',
14189 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
14192 'dir', 'menu', 'ol', 'ul', 'dl',
14198 Roo.HtmlEditorCore.black = [
14199 // 'embed', 'object', // enable - backend responsiblity to clean thiese
14201 'base', 'basefont', 'bgsound', 'blink', 'body',
14202 'frame', 'frameset', 'head', 'html', 'ilayer',
14203 'iframe', 'layer', 'link', 'meta', 'object',
14204 'script', 'style' ,'title', 'xml' // clean later..
14206 Roo.HtmlEditorCore.clean = [
14207 'script', 'style', 'title', 'xml'
14209 Roo.HtmlEditorCore.remove = [
14214 Roo.HtmlEditorCore.ablack = [
14218 Roo.HtmlEditorCore.aclean = [
14219 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
14223 Roo.HtmlEditorCore.pwhite= [
14224 'http', 'https', 'mailto'
14227 // white listed style attributes.
14228 Roo.HtmlEditorCore.cwhite= [
14229 // 'text-align', /// default is to allow most things..
14235 // black listed style attributes.
14236 Roo.HtmlEditorCore.cblack= [
14237 // 'font-size' -- this can be set by the project
14241 Roo.HtmlEditorCore.swapCodes =[
14260 * @class Roo.bootstrap.HtmlEditor
14261 * @extends Roo.bootstrap.TextArea
14262 * Bootstrap HtmlEditor class
14265 * Create a new HtmlEditor
14266 * @param {Object} config The config object
14269 Roo.bootstrap.HtmlEditor = function(config){
14270 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
14271 if (!this.toolbars) {
14272 this.toolbars = [];
14274 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
14277 * @event initialize
14278 * Fires when the editor is fully initialized (including the iframe)
14279 * @param {HtmlEditor} this
14284 * Fires when the editor is first receives the focus. Any insertion must wait
14285 * until after this event.
14286 * @param {HtmlEditor} this
14290 * @event beforesync
14291 * Fires before the textarea is updated with content from the editor iframe. Return false
14292 * to cancel the sync.
14293 * @param {HtmlEditor} this
14294 * @param {String} html
14298 * @event beforepush
14299 * Fires before the iframe editor is updated with content from the textarea. Return false
14300 * to cancel the push.
14301 * @param {HtmlEditor} this
14302 * @param {String} html
14307 * Fires when the textarea is updated with content from the editor iframe.
14308 * @param {HtmlEditor} this
14309 * @param {String} html
14314 * Fires when the iframe editor is updated with content from the textarea.
14315 * @param {HtmlEditor} this
14316 * @param {String} html
14320 * @event editmodechange
14321 * Fires when the editor switches edit modes
14322 * @param {HtmlEditor} this
14323 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
14325 editmodechange: true,
14327 * @event editorevent
14328 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
14329 * @param {HtmlEditor} this
14333 * @event firstfocus
14334 * Fires when on first focus - needed by toolbars..
14335 * @param {HtmlEditor} this
14340 * Auto save the htmlEditor value as a file into Events
14341 * @param {HtmlEditor} this
14345 * @event savedpreview
14346 * preview the saved version of htmlEditor
14347 * @param {HtmlEditor} this
14354 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
14358 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
14363 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
14368 * @cfg {Number} height (in pixels)
14372 * @cfg {Number} width (in pixels)
14377 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
14380 stylesheets: false,
14385 // private properties
14386 validationEvent : false,
14388 initialized : false,
14391 onFocus : Roo.emptyFn,
14393 hideMode:'offsets',
14396 tbContainer : false,
14398 toolbarContainer :function() {
14399 return this.wrap.select('.x-html-editor-tb',true).first();
14403 * Protected method that will not generally be called directly. It
14404 * is called when the editor creates its toolbar. Override this method if you need to
14405 * add custom toolbar buttons.
14406 * @param {HtmlEditor} editor
14408 createToolbar : function(){
14410 Roo.log("create toolbars");
14412 this.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard({editor: this} ) ];
14413 this.toolbars[0].render(this.toolbarContainer());
14417 // if (!editor.toolbars || !editor.toolbars.length) {
14418 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
14421 // for (var i =0 ; i < editor.toolbars.length;i++) {
14422 // editor.toolbars[i] = Roo.factory(
14423 // typeof(editor.toolbars[i]) == 'string' ?
14424 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
14425 // Roo.bootstrap.HtmlEditor);
14426 // editor.toolbars[i].init(editor);
14432 onRender : function(ct, position)
14434 // Roo.log("Call onRender: " + this.xtype);
14436 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
14438 this.wrap = this.inputEl().wrap({
14439 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
14442 this.editorcore.onRender(ct, position);
14444 if (this.resizable) {
14445 this.resizeEl = new Roo.Resizable(this.wrap, {
14449 minHeight : this.height,
14450 height: this.height,
14451 handles : this.resizable,
14454 resize : function(r, w, h) {
14455 _t.onResize(w,h); // -something
14461 this.createToolbar(this);
14464 if(!this.width && this.resizable){
14465 this.setSize(this.wrap.getSize());
14467 if (this.resizeEl) {
14468 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
14469 // should trigger onReize..
14475 onResize : function(w, h)
14477 Roo.log('resize: ' +w + ',' + h );
14478 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
14482 if(this.inputEl() ){
14483 if(typeof w == 'number'){
14484 var aw = w - this.wrap.getFrameWidth('lr');
14485 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
14488 if(typeof h == 'number'){
14489 var tbh = -11; // fixme it needs to tool bar size!
14490 for (var i =0; i < this.toolbars.length;i++) {
14491 // fixme - ask toolbars for heights?
14492 tbh += this.toolbars[i].el.getHeight();
14493 //if (this.toolbars[i].footer) {
14494 // tbh += this.toolbars[i].footer.el.getHeight();
14502 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
14503 ah -= 5; // knock a few pixes off for look..
14504 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
14508 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
14509 this.editorcore.onResize(ew,eh);
14514 * Toggles the editor between standard and source edit mode.
14515 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
14517 toggleSourceEdit : function(sourceEditMode)
14519 this.editorcore.toggleSourceEdit(sourceEditMode);
14521 if(this.editorcore.sourceEditMode){
14522 Roo.log('editor - showing textarea');
14525 // Roo.log(this.syncValue());
14527 this.inputEl().removeClass('hide');
14528 this.inputEl().dom.removeAttribute('tabIndex');
14529 this.inputEl().focus();
14531 Roo.log('editor - hiding textarea');
14533 // Roo.log(this.pushValue());
14536 this.inputEl().addClass('hide');
14537 this.inputEl().dom.setAttribute('tabIndex', -1);
14538 //this.deferFocus();
14541 if(this.resizable){
14542 this.setSize(this.wrap.getSize());
14545 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
14548 // private (for BoxComponent)
14549 adjustSize : Roo.BoxComponent.prototype.adjustSize,
14551 // private (for BoxComponent)
14552 getResizeEl : function(){
14556 // private (for BoxComponent)
14557 getPositionEl : function(){
14562 initEvents : function(){
14563 this.originalValue = this.getValue();
14567 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
14570 // markInvalid : Roo.emptyFn,
14572 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
14575 // clearInvalid : Roo.emptyFn,
14577 setValue : function(v){
14578 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
14579 this.editorcore.pushValue();
14584 deferFocus : function(){
14585 this.focus.defer(10, this);
14589 focus : function(){
14590 this.editorcore.focus();
14596 onDestroy : function(){
14602 for (var i =0; i < this.toolbars.length;i++) {
14603 // fixme - ask toolbars for heights?
14604 this.toolbars[i].onDestroy();
14607 this.wrap.dom.innerHTML = '';
14608 this.wrap.remove();
14613 onFirstFocus : function(){
14614 //Roo.log("onFirstFocus");
14615 this.editorcore.onFirstFocus();
14616 for (var i =0; i < this.toolbars.length;i++) {
14617 this.toolbars[i].onFirstFocus();
14623 syncValue : function()
14625 this.editorcore.syncValue();
14628 pushValue : function()
14630 this.editorcore.pushValue();
14634 // hide stuff that is not compatible
14648 * @event specialkey
14652 * @cfg {String} fieldClass @hide
14655 * @cfg {String} focusClass @hide
14658 * @cfg {String} autoCreate @hide
14661 * @cfg {String} inputType @hide
14664 * @cfg {String} invalidClass @hide
14667 * @cfg {String} invalidText @hide
14670 * @cfg {String} msgFx @hide
14673 * @cfg {String} validateOnBlur @hide
14684 * @class Roo.bootstrap.HtmlEditorToolbar1
14689 new Roo.bootstrap.HtmlEditor({
14692 new Roo.bootstrap.HtmlEditorToolbar1({
14693 disable : { fonts: 1 , format: 1, ..., ... , ...],
14699 * @cfg {Object} disable List of elements to disable..
14700 * @cfg {Array} btns List of additional buttons.
14704 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
14707 Roo.bootstrap.HtmlEditor.ToolbarStandard = function(config)
14710 Roo.apply(this, config);
14712 // default disabled, based on 'good practice'..
14713 this.disable = this.disable || {};
14714 Roo.applyIf(this.disable, {
14717 specialElements : true
14719 Roo.bootstrap.HtmlEditor.ToolbarStandard.superclass.constructor.call(this, config);
14721 this.editor = config.editor;
14722 this.editorcore = config.editor.editorcore;
14724 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
14726 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
14727 // dont call parent... till later.
14729 Roo.extend(Roo.bootstrap.HtmlEditor.ToolbarStandard, Roo.bootstrap.Navbar, {
14735 editorcore : false,
14740 "h1","h2","h3","h4","h5","h6",
14742 "abbr", "acronym", "address", "cite", "samp", "var",
14746 onRender : function(ct, position)
14748 // Roo.log("Call onRender: " + this.xtype);
14750 Roo.bootstrap.HtmlEditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
14752 this.el.dom.style.marginBottom = '0';
14754 var editorcore = this.editorcore;
14755 var editor= this.editor;
14758 var btn = function(id,cmd , toggle, handler){
14760 var event = toggle ? 'toggle' : 'click';
14765 xns: Roo.bootstrap,
14768 enableToggle:toggle !== false,
14770 pressed : toggle ? false : null,
14773 a.listeners[toggle ? 'toggle' : 'click'] = function() {
14774 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
14783 xns: Roo.bootstrap,
14784 glyphicon : 'font',
14788 xns: Roo.bootstrap,
14792 Roo.each(this.formats, function(f) {
14793 style.menu.items.push({
14795 xns: Roo.bootstrap,
14796 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
14801 editorcore.insertTag(this.tagname);
14808 children.push(style);
14811 btn('bold',false,true);
14812 btn('italic',false,true);
14813 btn('align-left', 'justifyleft',true);
14814 btn('align-center', 'justifycenter',true);
14815 btn('align-right' , 'justifyright',true);
14816 btn('link', false, false, function(btn) {
14817 //Roo.log("create link?");
14818 var url = prompt(this.createLinkText, this.defaultLinkValue);
14819 if(url && url != 'http:/'+'/'){
14820 this.editorcore.relayCmd('createlink', url);
14823 btn('list','insertunorderedlist',true);
14824 btn('pencil', false,true, function(btn){
14827 this.toggleSourceEdit(btn.pressed);
14833 xns: Roo.bootstrap,
14838 xns: Roo.bootstrap,
14843 cog.menu.items.push({
14845 xns: Roo.bootstrap,
14846 html : Clean styles,
14851 editorcore.insertTag(this.tagname);
14860 this.xtype = 'Navbar';
14862 for(var i=0;i< children.length;i++) {
14864 this.buttons.add(this.addxtypeChild(children[i]));
14868 editor.on('editorevent', this.updateToolbar, this);
14870 onBtnClick : function(id)
14872 this.editorcore.relayCmd(id);
14873 this.editorcore.focus();
14877 * Protected method that will not generally be called directly. It triggers
14878 * a toolbar update by reading the markup state of the current selection in the editor.
14880 updateToolbar: function(){
14882 if(!this.editorcore.activated){
14883 this.editor.onFirstFocus(); // is this neeed?
14887 var btns = this.buttons;
14888 var doc = this.editorcore.doc;
14889 btns.get('bold').setActive(doc.queryCommandState('bold'));
14890 btns.get('italic').setActive(doc.queryCommandState('italic'));
14891 //btns.get('underline').setActive(doc.queryCommandState('underline'));
14893 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
14894 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
14895 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
14897 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
14898 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
14901 var ans = this.editorcore.getAllAncestors();
14902 if (this.formatCombo) {
14905 var store = this.formatCombo.store;
14906 this.formatCombo.setValue("");
14907 for (var i =0; i < ans.length;i++) {
14908 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
14910 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
14918 // hides menus... - so this cant be on a menu...
14919 Roo.bootstrap.MenuMgr.hideAll();
14921 Roo.bootstrap.MenuMgr.hideAll();
14922 //this.editorsyncValue();
14924 onFirstFocus: function() {
14925 this.buttons.each(function(item){
14929 toggleSourceEdit : function(sourceEditMode){
14932 if(sourceEditMode){
14933 Roo.log("disabling buttons");
14934 this.buttons.each( function(item){
14935 if(item.cmd != 'pencil'){
14941 Roo.log("enabling buttons");
14942 if(this.editorcore.initialized){
14943 this.buttons.each( function(item){
14949 Roo.log("calling toggole on editor");
14950 // tell the editor that it's been pressed..
14951 this.editor.toggleSourceEdit(sourceEditMode);
14961 * @class Roo.bootstrap.Table.AbstractSelectionModel
14962 * @extends Roo.util.Observable
14963 * Abstract base class for grid SelectionModels. It provides the interface that should be
14964 * implemented by descendant classes. This class should not be directly instantiated.
14967 Roo.bootstrap.Table.AbstractSelectionModel = function(){
14968 this.locked = false;
14969 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
14973 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
14974 /** @ignore Called by the grid automatically. Do not call directly. */
14975 init : function(grid){
14981 * Locks the selections.
14984 this.locked = true;
14988 * Unlocks the selections.
14990 unlock : function(){
14991 this.locked = false;
14995 * Returns true if the selections are locked.
14996 * @return {Boolean}
14998 isLocked : function(){
14999 return this.locked;
15003 * @class Roo.bootstrap.Table.ColumnModel
15004 * @extends Roo.util.Observable
15005 * This is the default implementation of a ColumnModel used by the bootstrap table. It defines
15006 * the columns in the table.
15009 * @param {Object} config An Array of column config objects. See this class's
15010 * config objects for details.
15012 Roo.bootstrap.Table.ColumnModel = function(config){
15014 * The config passed into the constructor
15016 this.config = config;
15019 // if no id, create one
15020 // if the column does not have a dataIndex mapping,
15021 // map it to the order it is in the config
15022 for(var i = 0, len = config.length; i < len; i++){
15024 if(typeof c.dataIndex == "undefined"){
15027 if(typeof c.renderer == "string"){
15028 c.renderer = Roo.util.Format[c.renderer];
15030 if(typeof c.id == "undefined"){
15033 // if(c.editor && c.editor.xtype){
15034 // c.editor = Roo.factory(c.editor, Roo.grid);
15036 // if(c.editor && c.editor.isFormField){
15037 // c.editor = new Roo.grid.GridEditor(c.editor);
15040 this.lookup[c.id] = c;
15044 * The width of columns which have no width specified (defaults to 100)
15047 this.defaultWidth = 100;
15050 * Default sortable of columns which have no sortable specified (defaults to false)
15053 this.defaultSortable = false;
15057 * @event widthchange
15058 * Fires when the width of a column changes.
15059 * @param {ColumnModel} this
15060 * @param {Number} columnIndex The column index
15061 * @param {Number} newWidth The new width
15063 "widthchange": true,
15065 * @event headerchange
15066 * Fires when the text of a header changes.
15067 * @param {ColumnModel} this
15068 * @param {Number} columnIndex The column index
15069 * @param {Number} newText The new header text
15071 "headerchange": true,
15073 * @event hiddenchange
15074 * Fires when a column is hidden or "unhidden".
15075 * @param {ColumnModel} this
15076 * @param {Number} columnIndex The column index
15077 * @param {Boolean} hidden true if hidden, false otherwise
15079 "hiddenchange": true,
15081 * @event columnmoved
15082 * Fires when a column is moved.
15083 * @param {ColumnModel} this
15084 * @param {Number} oldIndex
15085 * @param {Number} newIndex
15087 "columnmoved" : true,
15089 * @event columlockchange
15090 * Fires when a column's locked state is changed
15091 * @param {ColumnModel} this
15092 * @param {Number} colIndex
15093 * @param {Boolean} locked true if locked
15095 "columnlockchange" : true
15097 Roo.bootstrap.Table.ColumnModel.superclass.constructor.call(this);
15099 Roo.extend(Roo.bootstrap.Table.ColumnModel, Roo.util.Observable, {
15101 * @cfg {String} header The header text to display in the Grid view.
15104 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
15105 * {@link Roo.data.Record} definition from which to draw the column's value. If not
15106 * specified, the column's index is used as an index into the Record's data Array.
15109 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
15110 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
15113 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
15114 * Defaults to the value of the {@link #defaultSortable} property.
15115 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
15118 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
15121 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
15124 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
15127 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
15130 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
15131 * given the cell's data value. See {@link #setRenderer}. If not specified, the
15132 * default renderer uses the raw data value.
15135 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
15139 * Returns the id of the column at the specified index.
15140 * @param {Number} index The column index
15141 * @return {String} the id
15143 getColumnId : function(index){
15144 return this.config[index].id;
15148 * Returns the column for a specified id.
15149 * @param {String} id The column id
15150 * @return {Object} the column
15152 getColumnById : function(id){
15153 return this.lookup[id];
15158 * Returns the column for a specified dataIndex.
15159 * @param {String} dataIndex The column dataIndex
15160 * @return {Object|Boolean} the column or false if not found
15162 getColumnByDataIndex: function(dataIndex){
15163 var index = this.findColumnIndex(dataIndex);
15164 return index > -1 ? this.config[index] : false;
15168 * Returns the index for a specified column id.
15169 * @param {String} id The column id
15170 * @return {Number} the index, or -1 if not found
15172 getIndexById : function(id){
15173 for(var i = 0, len = this.config.length; i < len; i++){
15174 if(this.config[i].id == id){
15182 * Returns the index for a specified column dataIndex.
15183 * @param {String} dataIndex The column dataIndex
15184 * @return {Number} the index, or -1 if not found
15187 findColumnIndex : function(dataIndex){
15188 for(var i = 0, len = this.config.length; i < len; i++){
15189 if(this.config[i].dataIndex == dataIndex){
15197 moveColumn : function(oldIndex, newIndex){
15198 var c = this.config[oldIndex];
15199 this.config.splice(oldIndex, 1);
15200 this.config.splice(newIndex, 0, c);
15201 this.dataMap = null;
15202 this.fireEvent("columnmoved", this, oldIndex, newIndex);
15205 isLocked : function(colIndex){
15206 return this.config[colIndex].locked === true;
15209 setLocked : function(colIndex, value, suppressEvent){
15210 if(this.isLocked(colIndex) == value){
15213 this.config[colIndex].locked = value;
15214 if(!suppressEvent){
15215 this.fireEvent("columnlockchange", this, colIndex, value);
15219 getTotalLockedWidth : function(){
15220 var totalWidth = 0;
15221 for(var i = 0; i < this.config.length; i++){
15222 if(this.isLocked(i) && !this.isHidden(i)){
15223 this.totalWidth += this.getColumnWidth(i);
15229 getLockedCount : function(){
15230 for(var i = 0, len = this.config.length; i < len; i++){
15231 if(!this.isLocked(i)){
15238 * Returns the number of columns.
15241 getColumnCount : function(visibleOnly){
15242 if(visibleOnly === true){
15244 for(var i = 0, len = this.config.length; i < len; i++){
15245 if(!this.isHidden(i)){
15251 return this.config.length;
15255 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
15256 * @param {Function} fn
15257 * @param {Object} scope (optional)
15258 * @return {Array} result
15260 getColumnsBy : function(fn, scope){
15262 for(var i = 0, len = this.config.length; i < len; i++){
15263 var c = this.config[i];
15264 if(fn.call(scope||this, c, i) === true){
15272 * Returns true if the specified column is sortable.
15273 * @param {Number} col The column index
15274 * @return {Boolean}
15276 isSortable : function(col){
15277 if(typeof this.config[col].sortable == "undefined"){
15278 return this.defaultSortable;
15280 return this.config[col].sortable;
15284 * Returns the rendering (formatting) function defined for the column.
15285 * @param {Number} col The column index.
15286 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
15288 getRenderer : function(col){
15289 if(!this.config[col].renderer){
15290 return Roo.bootstrap.Table.ColumnModel.defaultRenderer;
15292 return this.config[col].renderer;
15296 * Sets the rendering (formatting) function for a column.
15297 * @param {Number} col The column index
15298 * @param {Function} fn The function to use to process the cell's raw data
15299 * to return HTML markup for the grid view. The render function is called with
15300 * the following parameters:<ul>
15301 * <li>Data value.</li>
15302 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
15303 * <li>css A CSS style string to apply to the table cell.</li>
15304 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
15305 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
15306 * <li>Row index</li>
15307 * <li>Column index</li>
15308 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
15310 setRenderer : function(col, fn){
15311 this.config[col].renderer = fn;
15315 * Returns the width for the specified column.
15316 * @param {Number} col The column index
15319 getColumnWidth : function(col){
15320 return this.config[col].width * 1 || this.defaultWidth;
15324 * Sets the width for a column.
15325 * @param {Number} col The column index
15326 * @param {Number} width The new width
15328 setColumnWidth : function(col, width, suppressEvent){
15329 this.config[col].width = width;
15330 this.totalWidth = null;
15331 if(!suppressEvent){
15332 this.fireEvent("widthchange", this, col, width);
15337 * Returns the total width of all columns.
15338 * @param {Boolean} includeHidden True to include hidden column widths
15341 getTotalWidth : function(includeHidden){
15342 if(!this.totalWidth){
15343 this.totalWidth = 0;
15344 for(var i = 0, len = this.config.length; i < len; i++){
15345 if(includeHidden || !this.isHidden(i)){
15346 this.totalWidth += this.getColumnWidth(i);
15350 return this.totalWidth;
15354 * Returns the header for the specified column.
15355 * @param {Number} col The column index
15358 getColumnHeader : function(col){
15359 return this.config[col].header;
15363 * Sets the header for a column.
15364 * @param {Number} col The column index
15365 * @param {String} header The new header
15367 setColumnHeader : function(col, header){
15368 this.config[col].header = header;
15369 this.fireEvent("headerchange", this, col, header);
15373 * Returns the tooltip for the specified column.
15374 * @param {Number} col The column index
15377 getColumnTooltip : function(col){
15378 return this.config[col].tooltip;
15381 * Sets the tooltip for a column.
15382 * @param {Number} col The column index
15383 * @param {String} tooltip The new tooltip
15385 setColumnTooltip : function(col, tooltip){
15386 this.config[col].tooltip = tooltip;
15390 * Returns the dataIndex for the specified column.
15391 * @param {Number} col The column index
15394 getDataIndex : function(col){
15395 return this.config[col].dataIndex;
15399 * Sets the dataIndex for a column.
15400 * @param {Number} col The column index
15401 * @param {Number} dataIndex The new dataIndex
15403 setDataIndex : function(col, dataIndex){
15404 this.config[col].dataIndex = dataIndex;
15410 * Returns true if the cell is editable.
15411 * @param {Number} colIndex The column index
15412 * @param {Number} rowIndex The row index
15413 * @return {Boolean}
15415 isCellEditable : function(colIndex, rowIndex){
15416 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
15420 * Returns the editor defined for the cell/column.
15421 * return false or null to disable editing.
15422 * @param {Number} colIndex The column index
15423 * @param {Number} rowIndex The row index
15426 getCellEditor : function(colIndex, rowIndex){
15427 return this.config[colIndex].editor;
15431 * Sets if a column is editable.
15432 * @param {Number} col The column index
15433 * @param {Boolean} editable True if the column is editable
15435 setEditable : function(col, editable){
15436 this.config[col].editable = editable;
15441 * Returns true if the column is hidden.
15442 * @param {Number} colIndex The column index
15443 * @return {Boolean}
15445 isHidden : function(colIndex){
15446 return this.config[colIndex].hidden;
15451 * Returns true if the column width cannot be changed
15453 isFixed : function(colIndex){
15454 return this.config[colIndex].fixed;
15458 * Returns true if the column can be resized
15459 * @return {Boolean}
15461 isResizable : function(colIndex){
15462 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
15465 * Sets if a column is hidden.
15466 * @param {Number} colIndex The column index
15467 * @param {Boolean} hidden True if the column is hidden
15469 setHidden : function(colIndex, hidden){
15470 this.config[colIndex].hidden = hidden;
15471 this.totalWidth = null;
15472 this.fireEvent("hiddenchange", this, colIndex, hidden);
15476 * Sets the editor for a column.
15477 * @param {Number} col The column index
15478 * @param {Object} editor The editor object
15480 setEditor : function(col, editor){
15481 this.config[col].editor = editor;
15485 Roo.bootstrap.Table.ColumnModel.defaultRenderer = function(value){
15486 if(typeof value == "string" && value.length < 1){
15492 // Alias for backwards compatibility
15493 Roo.bootstrap.Table.DefaultColumnModel = Roo.bootstrap.Table.ColumnModel;
15496 * @extends Roo.bootstrap.Table.AbstractSelectionModel
15497 * @class Roo.bootstrap.Table.RowSelectionModel
15498 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
15499 * It supports multiple selections and keyboard selection/navigation.
15501 * @param {Object} config
15504 Roo.bootstrap.Table.RowSelectionModel = function(config){
15505 Roo.apply(this, config);
15506 this.selections = new Roo.util.MixedCollection(false, function(o){
15511 this.lastActive = false;
15515 * @event selectionchange
15516 * Fires when the selection changes
15517 * @param {SelectionModel} this
15519 "selectionchange" : true,
15521 * @event afterselectionchange
15522 * Fires after the selection changes (eg. by key press or clicking)
15523 * @param {SelectionModel} this
15525 "afterselectionchange" : true,
15527 * @event beforerowselect
15528 * Fires when a row is selected being selected, return false to cancel.
15529 * @param {SelectionModel} this
15530 * @param {Number} rowIndex The selected index
15531 * @param {Boolean} keepExisting False if other selections will be cleared
15533 "beforerowselect" : true,
15536 * Fires when a row is selected.
15537 * @param {SelectionModel} this
15538 * @param {Number} rowIndex The selected index
15539 * @param {Roo.data.Record} r The record
15541 "rowselect" : true,
15543 * @event rowdeselect
15544 * Fires when a row is deselected.
15545 * @param {SelectionModel} this
15546 * @param {Number} rowIndex The selected index
15548 "rowdeselect" : true
15550 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
15551 this.locked = false;
15554 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
15556 * @cfg {Boolean} singleSelect
15557 * True to allow selection of only one row at a time (defaults to false)
15559 singleSelect : false,
15562 initEvents : function(){
15564 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
15565 this.grid.on("mousedown", this.handleMouseDown, this);
15566 }else{ // allow click to work like normal
15567 this.grid.on("rowclick", this.handleDragableRowClick, this);
15570 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
15571 "up" : function(e){
15573 this.selectPrevious(e.shiftKey);
15574 }else if(this.last !== false && this.lastActive !== false){
15575 var last = this.last;
15576 this.selectRange(this.last, this.lastActive-1);
15577 this.grid.getView().focusRow(this.lastActive);
15578 if(last !== false){
15582 this.selectFirstRow();
15584 this.fireEvent("afterselectionchange", this);
15586 "down" : function(e){
15588 this.selectNext(e.shiftKey);
15589 }else if(this.last !== false && this.lastActive !== false){
15590 var last = this.last;
15591 this.selectRange(this.last, this.lastActive+1);
15592 this.grid.getView().focusRow(this.lastActive);
15593 if(last !== false){
15597 this.selectFirstRow();
15599 this.fireEvent("afterselectionchange", this);
15604 var view = this.grid.view;
15605 view.on("refresh", this.onRefresh, this);
15606 view.on("rowupdated", this.onRowUpdated, this);
15607 view.on("rowremoved", this.onRemove, this);
15611 onRefresh : function(){
15612 var ds = this.grid.dataSource, i, v = this.grid.view;
15613 var s = this.selections;
15614 s.each(function(r){
15615 if((i = ds.indexOfId(r.id)) != -1){
15624 onRemove : function(v, index, r){
15625 this.selections.remove(r);
15629 onRowUpdated : function(v, index, r){
15630 if(this.isSelected(r)){
15631 v.onRowSelect(index);
15637 * @param {Array} records The records to select
15638 * @param {Boolean} keepExisting (optional) True to keep existing selections
15640 selectRecords : function(records, keepExisting){
15642 this.clearSelections();
15644 var ds = this.grid.dataSource;
15645 for(var i = 0, len = records.length; i < len; i++){
15646 this.selectRow(ds.indexOf(records[i]), true);
15651 * Gets the number of selected rows.
15654 getCount : function(){
15655 return this.selections.length;
15659 * Selects the first row in the grid.
15661 selectFirstRow : function(){
15666 * Select the last row.
15667 * @param {Boolean} keepExisting (optional) True to keep existing selections
15669 selectLastRow : function(keepExisting){
15670 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
15674 * Selects the row immediately following the last selected row.
15675 * @param {Boolean} keepExisting (optional) True to keep existing selections
15677 selectNext : function(keepExisting){
15678 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
15679 this.selectRow(this.last+1, keepExisting);
15680 this.grid.getView().focusRow(this.last);
15685 * Selects the row that precedes the last selected row.
15686 * @param {Boolean} keepExisting (optional) True to keep existing selections
15688 selectPrevious : function(keepExisting){
15690 this.selectRow(this.last-1, keepExisting);
15691 this.grid.getView().focusRow(this.last);
15696 * Returns the selected records
15697 * @return {Array} Array of selected records
15699 getSelections : function(){
15700 return [].concat(this.selections.items);
15704 * Returns the first selected record.
15707 getSelected : function(){
15708 return this.selections.itemAt(0);
15713 * Clears all selections.
15715 clearSelections : function(fast){
15716 if(this.locked) return;
15718 var ds = this.grid.dataSource;
15719 var s = this.selections;
15720 s.each(function(r){
15721 this.deselectRow(ds.indexOfId(r.id));
15725 this.selections.clear();
15732 * Selects all rows.
15734 selectAll : function(){
15735 if(this.locked) return;
15736 this.selections.clear();
15737 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
15738 this.selectRow(i, true);
15743 * Returns True if there is a selection.
15744 * @return {Boolean}
15746 hasSelection : function(){
15747 return this.selections.length > 0;
15751 * Returns True if the specified row is selected.
15752 * @param {Number/Record} record The record or index of the record to check
15753 * @return {Boolean}
15755 isSelected : function(index){
15756 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
15757 return (r && this.selections.key(r.id) ? true : false);
15761 * Returns True if the specified record id is selected.
15762 * @param {String} id The id of record to check
15763 * @return {Boolean}
15765 isIdSelected : function(id){
15766 return (this.selections.key(id) ? true : false);
15770 handleMouseDown : function(e, t){
15771 var view = this.grid.getView(), rowIndex;
15772 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
15775 if(e.shiftKey && this.last !== false){
15776 var last = this.last;
15777 this.selectRange(last, rowIndex, e.ctrlKey);
15778 this.last = last; // reset the last
15779 view.focusRow(rowIndex);
15781 var isSelected = this.isSelected(rowIndex);
15782 if(e.button !== 0 && isSelected){
15783 view.focusRow(rowIndex);
15784 }else if(e.ctrlKey && isSelected){
15785 this.deselectRow(rowIndex);
15786 }else if(!isSelected){
15787 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
15788 view.focusRow(rowIndex);
15791 this.fireEvent("afterselectionchange", this);
15794 handleDragableRowClick : function(grid, rowIndex, e)
15796 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
15797 this.selectRow(rowIndex, false);
15798 grid.view.focusRow(rowIndex);
15799 this.fireEvent("afterselectionchange", this);
15804 * Selects multiple rows.
15805 * @param {Array} rows Array of the indexes of the row to select
15806 * @param {Boolean} keepExisting (optional) True to keep existing selections
15808 selectRows : function(rows, keepExisting){
15810 this.clearSelections();
15812 for(var i = 0, len = rows.length; i < len; i++){
15813 this.selectRow(rows[i], true);
15818 * Selects a range of rows. All rows in between startRow and endRow are also selected.
15819 * @param {Number} startRow The index of the first row in the range
15820 * @param {Number} endRow The index of the last row in the range
15821 * @param {Boolean} keepExisting (optional) True to retain existing selections
15823 selectRange : function(startRow, endRow, keepExisting){
15824 if(this.locked) return;
15826 this.clearSelections();
15828 if(startRow <= endRow){
15829 for(var i = startRow; i <= endRow; i++){
15830 this.selectRow(i, true);
15833 for(var i = startRow; i >= endRow; i--){
15834 this.selectRow(i, true);
15840 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
15841 * @param {Number} startRow The index of the first row in the range
15842 * @param {Number} endRow The index of the last row in the range
15844 deselectRange : function(startRow, endRow, preventViewNotify){
15845 if(this.locked) return;
15846 for(var i = startRow; i <= endRow; i++){
15847 this.deselectRow(i, preventViewNotify);
15853 * @param {Number} row The index of the row to select
15854 * @param {Boolean} keepExisting (optional) True to keep existing selections
15856 selectRow : function(index, keepExisting, preventViewNotify){
15857 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
15858 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
15859 if(!keepExisting || this.singleSelect){
15860 this.clearSelections();
15862 var r = this.grid.dataSource.getAt(index);
15863 this.selections.add(r);
15864 this.last = this.lastActive = index;
15865 if(!preventViewNotify){
15866 this.grid.getView().onRowSelect(index);
15868 this.fireEvent("rowselect", this, index, r);
15869 this.fireEvent("selectionchange", this);
15875 * @param {Number} row The index of the row to deselect
15877 deselectRow : function(index, preventViewNotify){
15878 if(this.locked) return;
15879 if(this.last == index){
15882 if(this.lastActive == index){
15883 this.lastActive = false;
15885 var r = this.grid.dataSource.getAt(index);
15886 this.selections.remove(r);
15887 if(!preventViewNotify){
15888 this.grid.getView().onRowDeselect(index);
15890 this.fireEvent("rowdeselect", this, index);
15891 this.fireEvent("selectionchange", this);
15895 restoreLast : function(){
15897 this.last = this._last;
15902 acceptsNav : function(row, col, cm){
15903 return !cm.isHidden(col) && cm.isCellEditable(col, row);
15907 onEditorKey : function(field, e){
15908 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
15913 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
15915 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
15917 }else if(k == e.ENTER && !e.ctrlKey){
15921 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
15923 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
15925 }else if(k == e.ESC){
15929 g.startEditing(newCell[0], newCell[1]);
15940 * @class Roo.bootstrap.MessageBar
15941 * @extends Roo.bootstrap.Component
15942 * Bootstrap MessageBar class
15943 * @cfg {String} html contents of the MessageBar
15944 * @cfg {String} weight (info | success | warning | danger) default info
15945 * @cfg {String} beforeClass insert the bar before the given class
15946 * @cfg {Boolean} closable (true | false) default false
15947 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
15950 * Create a new Element
15951 * @param {Object} config The config object
15954 Roo.bootstrap.MessageBar = function(config){
15955 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
15958 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
15964 beforeClass: 'bootstrap-sticky-wrap',
15966 getAutoCreate : function(){
15970 cls: 'alert alert-dismissable alert-' + this.weight,
15975 html: this.html || ''
15981 cfg.cls += ' alert-messages-fixed';
15995 onRender : function(ct, position)
15997 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
16000 var cfg = Roo.apply({}, this.getAutoCreate());
16004 cfg.cls += ' ' + this.cls;
16007 cfg.style = this.style;
16009 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
16011 this.el.setVisibilityMode(Roo.Element.DISPLAY);
16014 this.el.select('>button.close').on('click', this.hide, this);
16020 if (!this.rendered) {
16026 this.fireEvent('show', this);
16032 if (!this.rendered) {
16038 this.fireEvent('hide', this);
16041 update : function()
16043 // var e = this.el.dom.firstChild;
16045 // if(this.closable){
16046 // e = e.nextSibling;
16049 // e.data = this.html || '';
16051 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';