4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
21 * Do not use directly - it does not do anything..
22 * @param {Object} config The config object
27 Roo.bootstrap.Component = function(config){
28 Roo.bootstrap.Component.superclass.constructor.call(this, config);
31 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
34 allowDomMove : false, // to stop relocations in parent onRender...
42 initEvents : function() { },
48 can_build_overlaid : true,
55 // returns the parent component..
56 return Roo.ComponentMgr.get(this.parentId)
62 onRender : function(ct, position)
64 // Roo.log("Call onRender: " + this.xtype);
66 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
69 if (this.el.attr('xtype')) {
70 this.el.attr('xtypex', this.el.attr('xtype'));
71 this.el.dom.removeAttribute('xtype');
81 var cfg = Roo.apply({}, this.getAutoCreate());
84 // fill in the extra attributes
85 if (this.xattr && typeof(this.xattr) =='object') {
86 for (var i in this.xattr) {
87 cfg[i] = this.xattr[i];
92 cfg.dataId = this.dataId;
96 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
99 if (this.style) { // fixme needs to support more complex style data.
100 cfg.style = this.style;
104 cfg.name = this.name;
107 this.el = ct.createChild(cfg, position);
109 if(this.tabIndex !== undefined){
110 this.el.dom.setAttribute('tabIndex', this.tabIndex);
117 getChildContainer : function()
123 addxtype : function(tree,cntr)
127 cn = Roo.factory(tree);
129 cn.parentType = this.xtype; //??
130 cn.parentId = this.id;
132 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
134 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
136 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
138 var build_from_html = Roo.XComponent.build_from_html;
140 var is_body = (tree.xtype == 'Body') ;
142 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
144 var self_cntr_el = Roo.get(this[cntr]());
146 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
147 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
148 return this.addxtypeChild(tree,cntr);
151 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
154 return this.addxtypeChild(Roo.apply({}, tree),cntr);
157 Roo.log('skipping render');
165 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
171 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
175 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
180 addxtypeChild : function (tree, cntr)
182 Roo.log('addxtypeChild:' + cntr);
184 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
187 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
188 (typeof(tree['flexy:foreach']) != 'undefined');
193 // render the element if it's not BODY.
194 if (tree.xtype != 'Body') {
196 cn = Roo.factory(tree);
198 cn.parentType = this.xtype; //??
199 cn.parentId = this.id;
201 var build_from_html = Roo.XComponent.build_from_html;
204 // does the container contain child eleemnts with 'xtype' attributes.
205 // that match this xtype..
206 // note - when we render we create these as well..
207 // so we should check to see if body has xtype set.
208 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
210 var self_cntr_el = Roo.get(this[cntr]());
211 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
213 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
214 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
220 //echild.dom.removeAttribute('xtype');
222 Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
229 // if object has flexy:if - then it may or may not be rendered.
230 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
231 // skip a flexy if element.
232 Roo.log('skipping render');
235 // actually if flexy:foreach is found, we really want to create
236 // multiple copies here...
238 //Roo.log(this[cntr]());
239 cn.render(this[cntr]());
241 // then add the element..
248 if (typeof (tree.menu) != 'undefined') {
249 tree.menu.parentType = cn.xtype;
250 tree.menu.triggerEl = cn.el;
251 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
255 if (!tree.items || !tree.items.length) {
259 var items = tree.items;
262 //Roo.log(items.length);
264 for(var i =0;i < items.length;i++) {
265 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
286 * @class Roo.bootstrap.Body
287 * @extends Roo.bootstrap.Component
288 * Bootstrap Body class
292 * @param {Object} config The config object
295 Roo.bootstrap.Body = function(config){
296 Roo.bootstrap.Body.superclass.constructor.call(this, config);
297 this.el = Roo.get(document.body);
298 if (this.cls && this.cls.length) {
299 Roo.get(document.body).addClass(this.cls);
303 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
308 onRender : function(ct, position)
310 /* Roo.log("Roo.bootstrap.Body - onRender");
311 if (this.cls && this.cls.length) {
312 Roo.get(document.body).addClass(this.cls);
332 * @class Roo.bootstrap.ButtonGroup
333 * @extends Roo.bootstrap.Component
334 * Bootstrap ButtonGroup class
335 * @cfg {String} size lg | sm | xs (default empty normal)
336 * @cfg {String} align vertical | justified (default none)
337 * @cfg {String} direction up | down (default down)
338 * @cfg {Boolean} toolbar false | true
339 * @cfg {Boolean} btn true | false
344 * @param {Object} config The config object
347 Roo.bootstrap.ButtonGroup = function(config){
348 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
351 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
359 getAutoCreate : function(){
365 cfg.html = this.html || cfg.html;
376 if (['vertical','justified'].indexOf(this.align)!==-1) {
377 cfg.cls = 'btn-group-' + this.align;
379 if (this.align == 'justified') {
380 console.log(this.items);
384 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
385 cfg.cls += ' btn-group-' + this.size;
388 if (this.direction == 'up') {
389 cfg.cls += ' dropup' ;
405 * @class Roo.bootstrap.Button
406 * @extends Roo.bootstrap.Component
407 * Bootstrap Button class
408 * @cfg {String} html The button content
409 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger | link
410 * @cfg {String} size empty | lg | sm | xs
411 * @cfg {String} tag empty | a | input | submit
412 * @cfg {String} href empty or href
413 * @cfg {Boolean} disabled false | true
414 * @cfg {Boolean} isClose false | true
415 * @cfg {String} glyphicon empty | adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out
416 * @cfg {String} badge text for badge
417 * @cfg {String} theme default (or empty) | glow
418 * @cfg {Boolean} inverse false | true
419 * @cfg {Boolean} toggle false | true
420 * @cfg {String} ontext text for on toggle state
421 * @cfg {String} offtext text for off toggle state
422 * @cfg {Boolean} defaulton true | false
423 * @cfg {Boolean} preventDefault (true | false) default true
424 * @cfg {Boolean} removeClass true | false remove the standard class..
425 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
428 * Create a new button
429 * @param {Object} config The config object
433 Roo.bootstrap.Button = function(config){
434 Roo.bootstrap.Button.superclass.constructor.call(this, config);
439 * When a butotn is pressed
440 * @param {Roo.EventObject} e
445 * After the button has been toggles
446 * @param {Roo.EventObject} e
447 * @param {boolean} pressed (also available as button.pressed)
453 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
471 preventDefault: true,
480 getAutoCreate : function(){
488 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
489 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
494 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
496 if (this.toggle == true) {
499 cls: 'slider-frame roo-button',
504 'data-off-text':'OFF',
505 cls: 'slider-button',
511 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
512 cfg.cls += ' '+this.weight;
521 cfg["aria-hidden"] = true;
523 cfg.html = "×";
529 if (this.theme==='default') {
530 cfg.cls = 'btn roo-button';
532 //if (this.parentType != 'Navbar') {
533 this.weight = this.weight.length ? this.weight : 'default';
535 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
537 cfg.cls += ' btn-' + this.weight;
539 } else if (this.theme==='glow') {
542 cfg.cls = 'btn-glow roo-button';
544 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
546 cfg.cls += ' ' + this.weight;
552 this.cls += ' inverse';
557 cfg.cls += ' active';
561 cfg.disabled = 'disabled';
565 Roo.log('changing to ul' );
567 this.glyphicon = 'caret';
570 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
572 //gsRoo.log(this.parentType);
573 if (this.parentType === 'Navbar' && !this.parent().bar) {
574 Roo.log('changing to li?');
583 href : this.href || '#'
586 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
587 cfg.cls += ' dropdown';
594 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
596 if (this.glyphicon) {
597 cfg.html = ' ' + cfg.html;
602 cls: 'glyphicon glyphicon-' + this.glyphicon
612 // cfg.cls='btn roo-button';
616 var value = cfg.html;
621 cls: 'glyphicon glyphicon-' + this.glyphicon,
640 cfg.cls += ' dropdown';
641 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
644 if (cfg.tag !== 'a' && this.href !== '') {
645 throw "Tag must be a to set href.";
646 } else if (this.href.length > 0) {
647 cfg.href = this.href;
650 if(this.removeClass){
655 cfg.target = this.target;
660 initEvents: function() {
661 // Roo.log('init events?');
662 // Roo.log(this.el.dom);
663 if (this.el.hasClass('roo-button')) {
664 this.el.on('click', this.onClick, this);
666 this.el.select('.roo-button').on('click', this.onClick, this);
669 if(this.removeClass){
670 this.el.on('click', this.onClick, this);
673 this.el.enableDisplayMode();
676 onClick : function(e)
682 Roo.log('button on click ');
683 if(this.preventDefault){
686 if (this.pressed === true || this.pressed === false) {
687 this.pressed = !this.pressed;
688 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
689 this.fireEvent('toggle', this, e, this.pressed);
693 this.fireEvent('click', this, e);
697 * Enables this button
701 this.disabled = false;
702 this.el.removeClass('disabled');
706 * Disable this button
710 this.disabled = true;
711 this.el.addClass('disabled');
714 * sets the active state on/off,
715 * @param {Boolean} state (optional) Force a particular state
717 setActive : function(v) {
719 this.el[v ? 'addClass' : 'removeClass']('active');
722 * toggles the current active state
724 toggleActive : function()
726 var active = this.el.hasClass('active');
727 this.setActive(!active);
731 setText : function(str)
733 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
756 * @class Roo.bootstrap.Column
757 * @extends Roo.bootstrap.Component
758 * Bootstrap Column class
759 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
760 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
761 * @cfg {Number} md colspan out of 12 for computer-sized screens
762 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
763 * @cfg {String} html content of column.
766 * Create a new Column
767 * @param {Object} config The config object
770 Roo.bootstrap.Column = function(config){
771 Roo.bootstrap.Column.superclass.constructor.call(this, config);
774 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
783 getAutoCreate : function(){
784 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
792 ['xs','sm','md','lg'].map(function(size){
793 if (settings[size]) {
794 cfg.cls += ' col-' + size + '-' + settings[size];
797 if (this.html.length) {
798 cfg.html = this.html;
817 * @class Roo.bootstrap.Container
818 * @extends Roo.bootstrap.Component
819 * Bootstrap Container class
820 * @cfg {Boolean} jumbotron is it a jumbotron element
821 * @cfg {String} html content of element
822 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
823 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
824 * @cfg {String} header content of header (for panel)
825 * @cfg {String} footer content of footer (for panel)
826 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
827 * @cfg {String} tag (header|aside|section) type of HTML tag.
831 * Create a new Container
832 * @param {Object} config The config object
835 Roo.bootstrap.Container = function(config){
836 Roo.bootstrap.Container.superclass.constructor.call(this, config);
839 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
850 getChildContainer : function() {
856 if (this.panel.length) {
857 return this.el.select('.panel-body',true).first();
864 getAutoCreate : function(){
867 tag : this.tag || 'div',
871 if (this.jumbotron) {
872 cfg.cls = 'jumbotron';
874 // - this is applied by the parent..
876 // cfg.cls = this.cls + '';
879 if (this.sticky.length) {
881 var bd = Roo.get(document.body);
882 if (!bd.hasClass('bootstrap-sticky')) {
883 bd.addClass('bootstrap-sticky');
884 Roo.select('html',true).setStyle('height', '100%');
887 cfg.cls += 'bootstrap-sticky-' + this.sticky;
891 if (this.well.length) {
895 cfg.cls +=' well well-' +this.well;
905 if (this.panel.length) {
906 cfg.cls += ' panel panel-' + this.panel;
908 if (this.header.length) {
911 cls : 'panel-heading',
927 if (this.footer.length) {
929 cls : 'panel-footer',
938 body.html = this.html || cfg.html;
940 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
941 cfg.cls = 'container';
958 * @class Roo.bootstrap.Img
959 * @extends Roo.bootstrap.Component
960 * Bootstrap Img class
961 * @cfg {Boolean} imgResponsive false | true
962 * @cfg {String} border rounded | circle | thumbnail
963 * @cfg {String} src image source
964 * @cfg {String} alt image alternative text
965 * @cfg {String} href a tag href
966 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
970 * @param {Object} config The config object
973 Roo.bootstrap.Img = function(config){
974 Roo.bootstrap.Img.superclass.constructor.call(this, config);
980 * The img click event for the img.
981 * @param {Roo.EventObject} e
987 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
995 getAutoCreate : function(){
999 cls: (this.imgResponsive) ? 'img-responsive' : '',
1003 cfg.html = this.html || cfg.html;
1005 cfg.src = this.src || cfg.src;
1007 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1008 cfg.cls += ' img-' + this.border;
1025 a.target = this.target;
1031 return (this.href) ? a : cfg;
1034 initEvents: function() {
1037 this.el.on('click', this.onClick, this);
1041 onClick : function(e)
1043 Roo.log('img onclick');
1044 this.fireEvent('click', this, e);
1058 * @class Roo.bootstrap.Link
1059 * @extends Roo.bootstrap.Component
1060 * Bootstrap Link Class
1061 * @cfg {String} alt image alternative text
1062 * @cfg {String} href a tag href
1063 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1064 * @cfg {String} html the content of the link.
1068 * Create a new Input
1069 * @param {Object} config The config object
1072 Roo.bootstrap.Link = function(config){
1073 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1079 * The img click event for the img.
1080 * @param {Roo.EventObject} e
1086 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1091 getAutoCreate : function(){
1095 html : this.html || 'html-missing'
1102 cfg.href = this.href || '#';
1104 cfg.target = this.target;
1110 initEvents: function() {
1113 this.el.on('click', this.onClick, this);
1117 onClick : function(e)
1119 //Roo.log('img onclick');
1120 this.fireEvent('click', this, e);
1133 * @class Roo.bootstrap.Header
1134 * @extends Roo.bootstrap.Component
1135 * Bootstrap Header class
1136 * @cfg {String} html content of header
1137 * @cfg {Number} level (1|2|3|4|5|6) default 1
1140 * Create a new Header
1141 * @param {Object} config The config object
1145 Roo.bootstrap.Header = function(config){
1146 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1149 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1157 getAutoCreate : function(){
1160 tag: 'h' + (1 *this.level),
1161 html: this.html || 'fill in html'
1173 * Ext JS Library 1.1.1
1174 * Copyright(c) 2006-2007, Ext JS, LLC.
1176 * Originally Released Under LGPL - original licence link has changed is not relivant.
1179 * <script type="text/javascript">
1183 * @class Roo.bootstrap.MenuMgr
1184 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1187 Roo.bootstrap.MenuMgr = function(){
1188 var menus, active, groups = {}, attached = false, lastShow = new Date();
1190 // private - called when first menu is created
1193 active = new Roo.util.MixedCollection();
1194 Roo.get(document).addKeyListener(27, function(){
1195 if(active.length > 0){
1203 if(active && active.length > 0){
1204 var c = active.clone();
1214 if(active.length < 1){
1215 Roo.get(document).un("mouseup", onMouseDown);
1223 var last = active.last();
1224 lastShow = new Date();
1227 Roo.get(document).on("mouseup", onMouseDown);
1232 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1233 m.parentMenu.activeChild = m;
1234 }else if(last && last.isVisible()){
1235 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1240 function onBeforeHide(m){
1242 m.activeChild.hide();
1244 if(m.autoHideTimer){
1245 clearTimeout(m.autoHideTimer);
1246 delete m.autoHideTimer;
1251 function onBeforeShow(m){
1252 var pm = m.parentMenu;
1253 if(!pm && !m.allowOtherMenus){
1255 }else if(pm && pm.activeChild && active != m){
1256 pm.activeChild.hide();
1261 function onMouseDown(e){
1262 Roo.log("on MouseDown");
1263 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1271 function onBeforeCheck(mi, state){
1273 var g = groups[mi.group];
1274 for(var i = 0, l = g.length; i < l; i++){
1276 g[i].setChecked(false);
1285 * Hides all menus that are currently visible
1287 hideAll : function(){
1292 register : function(menu){
1296 menus[menu.id] = menu;
1297 menu.on("beforehide", onBeforeHide);
1298 menu.on("hide", onHide);
1299 menu.on("beforeshow", onBeforeShow);
1300 menu.on("show", onShow);
1302 if(g && menu.events["checkchange"]){
1306 groups[g].push(menu);
1307 menu.on("checkchange", onCheck);
1312 * Returns a {@link Roo.menu.Menu} object
1313 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1314 * be used to generate and return a new Menu instance.
1316 get : function(menu){
1317 if(typeof menu == "string"){ // menu id
1319 }else if(menu.events){ // menu instance
1322 /*else if(typeof menu.length == 'number'){ // array of menu items?
1323 return new Roo.bootstrap.Menu({items:menu});
1324 }else{ // otherwise, must be a config
1325 return new Roo.bootstrap.Menu(menu);
1332 unregister : function(menu){
1333 delete menus[menu.id];
1334 menu.un("beforehide", onBeforeHide);
1335 menu.un("hide", onHide);
1336 menu.un("beforeshow", onBeforeShow);
1337 menu.un("show", onShow);
1339 if(g && menu.events["checkchange"]){
1340 groups[g].remove(menu);
1341 menu.un("checkchange", onCheck);
1346 registerCheckable : function(menuItem){
1347 var g = menuItem.group;
1352 groups[g].push(menuItem);
1353 menuItem.on("beforecheckchange", onBeforeCheck);
1358 unregisterCheckable : function(menuItem){
1359 var g = menuItem.group;
1361 groups[g].remove(menuItem);
1362 menuItem.un("beforecheckchange", onBeforeCheck);
1374 * @class Roo.bootstrap.Menu
1375 * @extends Roo.bootstrap.Component
1376 * Bootstrap Menu class - container for MenuItems
1377 * @cfg {String} type type of menu
1381 * @param {Object} config The config object
1385 Roo.bootstrap.Menu = function(config){
1386 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1387 if (this.registerMenu) {
1388 Roo.bootstrap.MenuMgr.register(this);
1393 * Fires before this menu is displayed
1394 * @param {Roo.menu.Menu} this
1399 * Fires before this menu is hidden
1400 * @param {Roo.menu.Menu} this
1405 * Fires after this menu is displayed
1406 * @param {Roo.menu.Menu} this
1411 * Fires after this menu is hidden
1412 * @param {Roo.menu.Menu} this
1417 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1418 * @param {Roo.menu.Menu} this
1419 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1420 * @param {Roo.EventObject} e
1425 * Fires when the mouse is hovering over this menu
1426 * @param {Roo.menu.Menu} this
1427 * @param {Roo.EventObject} e
1428 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1433 * Fires when the mouse exits this menu
1434 * @param {Roo.menu.Menu} this
1435 * @param {Roo.EventObject} e
1436 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1441 * Fires when a menu item contained in this menu is clicked
1442 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1443 * @param {Roo.EventObject} e
1447 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1450 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1454 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1457 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1459 registerMenu : true,
1461 menuItems :false, // stores the menu items..
1467 getChildContainer : function() {
1471 getAutoCreate : function(){
1473 //if (['right'].indexOf(this.align)!==-1) {
1474 // cfg.cn[1].cls += ' pull-right'
1478 cls : 'dropdown-menu' ,
1479 style : 'z-index:1000'
1483 if (this.type === 'submenu') {
1484 cfg.cls = 'submenu active'
1489 initEvents : function() {
1491 // Roo.log("ADD event");
1492 // Roo.log(this.triggerEl.dom);
1493 this.triggerEl.on('click', this.onTriggerPress, this);
1494 this.triggerEl.addClass('dropdown-toggle');
1495 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1497 this.el.on("mouseover", this.onMouseOver, this);
1498 this.el.on("mouseout", this.onMouseOut, this);
1502 findTargetItem : function(e){
1503 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1507 //Roo.log(t); Roo.log(t.id);
1509 //Roo.log(this.menuitems);
1510 return this.menuitems.get(t.id);
1512 //return this.items.get(t.menuItemId);
1517 onClick : function(e){
1518 Roo.log("menu.onClick");
1519 var t = this.findTargetItem(e);
1525 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1526 if(t == this.activeItem && t.shouldDeactivate(e)){
1527 this.activeItem.deactivate();
1528 delete this.activeItem;
1532 this.setActiveItem(t, true);
1539 Roo.log('pass click event');
1543 this.fireEvent("click", this, t, e);
1547 onMouseOver : function(e){
1548 var t = this.findTargetItem(e);
1551 // if(t.canActivate && !t.disabled){
1552 // this.setActiveItem(t, true);
1556 this.fireEvent("mouseover", this, e, t);
1558 isVisible : function(){
1559 return !this.hidden;
1561 onMouseOut : function(e){
1562 var t = this.findTargetItem(e);
1565 // if(t == this.activeItem && t.shouldDeactivate(e)){
1566 // this.activeItem.deactivate();
1567 // delete this.activeItem;
1570 this.fireEvent("mouseout", this, e, t);
1575 * Displays this menu relative to another element
1576 * @param {String/HTMLElement/Roo.Element} element The element to align to
1577 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1578 * the element (defaults to this.defaultAlign)
1579 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1581 show : function(el, pos, parentMenu){
1582 this.parentMenu = parentMenu;
1586 this.fireEvent("beforeshow", this);
1587 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1590 * Displays this menu at a specific xy position
1591 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1592 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1594 showAt : function(xy, parentMenu, /* private: */_e){
1595 this.parentMenu = parentMenu;
1600 this.fireEvent("beforeshow", this);
1602 //xy = this.el.adjustForConstraints(xy);
1604 //this.el.setXY(xy);
1606 this.hideMenuItems();
1607 this.hidden = false;
1608 this.triggerEl.addClass('open');
1610 this.fireEvent("show", this);
1616 this.doFocus.defer(50, this);
1620 doFocus : function(){
1622 this.focusEl.focus();
1627 * Hides this menu and optionally all parent menus
1628 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1630 hide : function(deep){
1632 this.hideMenuItems();
1633 if(this.el && this.isVisible()){
1634 this.fireEvent("beforehide", this);
1635 if(this.activeItem){
1636 this.activeItem.deactivate();
1637 this.activeItem = null;
1639 this.triggerEl.removeClass('open');;
1641 this.fireEvent("hide", this);
1643 if(deep === true && this.parentMenu){
1644 this.parentMenu.hide(true);
1648 onTriggerPress : function(e)
1651 Roo.log('trigger press');
1652 //Roo.log(e.getTarget());
1653 // Roo.log(this.triggerEl.dom);
1654 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1657 if (this.isVisible()) {
1661 this.show(this.triggerEl, false, false);
1670 hideMenuItems : function()
1672 //$(backdrop).remove()
1673 Roo.select('.open',true).each(function(aa) {
1675 aa.removeClass('open');
1676 //var parent = getParent($(this))
1677 //var relatedTarget = { relatedTarget: this }
1679 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1680 //if (e.isDefaultPrevented()) return
1681 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1684 addxtypeChild : function (tree, cntr) {
1685 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1687 this.menuitems.add(comp);
1708 * @class Roo.bootstrap.MenuItem
1709 * @extends Roo.bootstrap.Component
1710 * Bootstrap MenuItem class
1711 * @cfg {String} html the menu label
1712 * @cfg {String} href the link
1713 * @cfg {Boolean} preventDefault (true | false) default true
1717 * Create a new MenuItem
1718 * @param {Object} config The config object
1722 Roo.bootstrap.MenuItem = function(config){
1723 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1728 * The raw click event for the entire grid.
1729 * @param {Roo.EventObject} e
1735 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1739 preventDefault: true,
1741 getAutoCreate : function(){
1744 cls: 'dropdown-menu-item',
1754 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1755 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1759 initEvents: function() {
1761 //this.el.select('a').on('click', this.onClick, this);
1764 onClick : function(e)
1766 Roo.log('item on click ');
1767 //if(this.preventDefault){
1768 // e.preventDefault();
1770 //this.parent().hideMenuItems();
1772 this.fireEvent('click', this, e);
1791 * @class Roo.bootstrap.MenuSeparator
1792 * @extends Roo.bootstrap.Component
1793 * Bootstrap MenuSeparator class
1796 * Create a new MenuItem
1797 * @param {Object} config The config object
1801 Roo.bootstrap.MenuSeparator = function(config){
1802 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1805 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1807 getAutoCreate : function(){
1822 <div class="modal fade">
1823 <div class="modal-dialog">
1824 <div class="modal-content">
1825 <div class="modal-header">
1826 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1827 <h4 class="modal-title">Modal title</h4>
1829 <div class="modal-body">
1830 <p>One fine body…</p>
1832 <div class="modal-footer">
1833 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1834 <button type="button" class="btn btn-primary">Save changes</button>
1836 </div><!-- /.modal-content -->
1837 </div><!-- /.modal-dialog -->
1838 </div><!-- /.modal -->
1848 * @class Roo.bootstrap.Modal
1849 * @extends Roo.bootstrap.Component
1850 * Bootstrap Modal class
1851 * @cfg {String} title Title of dialog
1852 * @cfg {Boolean} specificTitle (true|false) default false
1853 * @cfg {Array} buttons Array of buttons or standard button set..
1854 * @cfg {String} buttonPosition (left|right|center) default right
1857 * Create a new Modal Dialog
1858 * @param {Object} config The config object
1861 Roo.bootstrap.Modal = function(config){
1862 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1867 * The raw btnclick event for the button
1868 * @param {Roo.EventObject} e
1872 this.buttons = this.buttons || [];
1875 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1877 title : 'test dialog',
1884 specificTitle: false,
1886 buttonPosition: 'right',
1888 onRender : function(ct, position)
1890 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1893 var cfg = Roo.apply({}, this.getAutoCreate());
1896 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1898 //if (!cfg.name.length) {
1902 cfg.cls += ' ' + this.cls;
1905 cfg.style = this.style;
1907 this.el = Roo.get(document.body).createChild(cfg, position);
1909 //var type = this.el.dom.type;
1911 if(this.tabIndex !== undefined){
1912 this.el.dom.setAttribute('tabIndex', this.tabIndex);
1917 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1918 this.maskEl.enableDisplayMode("block");
1920 //this.el.addClass("x-dlg-modal");
1922 if (this.buttons.length) {
1923 Roo.each(this.buttons, function(bb) {
1924 b = Roo.apply({}, bb);
1925 b.xns = b.xns || Roo.bootstrap;
1926 b.xtype = b.xtype || 'Button';
1927 if (typeof(b.listeners) == 'undefined') {
1928 b.listeners = { click : this.onButtonClick.createDelegate(this) };
1931 var btn = Roo.factory(b);
1933 btn.onRender(this.el.select('.modal-footer div').first());
1937 // render the children.
1940 if(typeof(this.items) != 'undefined'){
1941 var items = this.items;
1944 for(var i =0;i < items.length;i++) {
1945 nitems.push(this.addxtype(Roo.apply({}, items[i])));
1949 this.items = nitems;
1951 this.body = this.el.select('.modal-body',true).first();
1952 this.close = this.el.select('.modal-header .close', true).first();
1953 this.footer = this.el.select('.modal-footer',true).first();
1955 //this.el.addClass([this.fieldClass, this.cls]);
1958 getAutoCreate : function(){
1963 html : this.html || ''
1968 cls : 'modal-title',
1972 if(this.specificTitle){
1978 style : 'display: none',
1981 cls: "modal-dialog",
1984 cls : "modal-content",
1987 cls : 'modal-header',
1999 cls : 'modal-footer',
2003 cls: 'btn-' + this.buttonPosition
2022 getChildContainer : function() {
2024 return this.el.select('.modal-body',true).first();
2027 getButtonContainer : function() {
2028 return this.el.select('.modal-footer div',true).first();
2031 initEvents : function()
2033 this.el.select('.modal-header .close').on('click', this.hide, this);
2035 // this.addxtype(this);
2039 if (!this.rendered) {
2043 this.el.addClass('on');
2044 this.el.removeClass('fade');
2045 this.el.setStyle('display', 'block');
2046 Roo.get(document.body).addClass("x-body-masked");
2047 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2049 this.el.setStyle('zIndex', '10001');
2050 this.fireEvent('show', this);
2056 Roo.log('Modal hide?!');
2058 Roo.get(document.body).removeClass("x-body-masked");
2059 this.el.removeClass('on');
2060 this.el.addClass('fade');
2061 this.el.setStyle('display', 'none');
2062 this.fireEvent('hide', this);
2065 addButton : function(str, cb)
2069 var b = Roo.apply({}, { html : str } );
2070 b.xns = b.xns || Roo.bootstrap;
2071 b.xtype = b.xtype || 'Button';
2072 if (typeof(b.listeners) == 'undefined') {
2073 b.listeners = { click : cb.createDelegate(this) };
2076 var btn = Roo.factory(b);
2078 btn.onRender(this.el.select('.modal-footer div').first());
2084 setDefaultButton : function(btn)
2086 //this.el.select('.modal-footer').()
2088 resizeTo: function(w,h)
2092 setContentSize : function(w, h)
2096 onButtonClick: function(btn,e)
2099 this.fireEvent('btnclick', btn.name, e);
2101 setTitle: function(str) {
2102 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2108 Roo.apply(Roo.bootstrap.Modal, {
2110 * Button config that displays a single OK button
2119 * Button config that displays Yes and No buttons
2135 * Button config that displays OK and Cancel buttons
2150 * Button config that displays Yes, No and Cancel buttons
2172 * messagebox - can be used as a replace
2176 * @class Roo.MessageBox
2177 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2181 Roo.Msg.alert('Status', 'Changes saved successfully.');
2183 // Prompt for user data:
2184 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2186 // process text value...
2190 // Show a dialog using config options:
2192 title:'Save Changes?',
2193 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2194 buttons: Roo.Msg.YESNOCANCEL,
2201 Roo.bootstrap.MessageBox = function(){
2202 var dlg, opt, mask, waitTimer;
2203 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2204 var buttons, activeTextEl, bwidth;
2208 var handleButton = function(button){
2210 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2214 var handleHide = function(){
2216 dlg.el.removeClass(opt.cls);
2219 // Roo.TaskMgr.stop(waitTimer);
2220 // waitTimer = null;
2225 var updateButtons = function(b){
2228 buttons["ok"].hide();
2229 buttons["cancel"].hide();
2230 buttons["yes"].hide();
2231 buttons["no"].hide();
2232 //dlg.footer.dom.style.display = 'none';
2235 dlg.footer.dom.style.display = '';
2236 for(var k in buttons){
2237 if(typeof buttons[k] != "function"){
2240 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2241 width += buttons[k].el.getWidth()+15;
2251 var handleEsc = function(d, k, e){
2252 if(opt && opt.closable !== false){
2262 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2263 * @return {Roo.BasicDialog} The BasicDialog element
2265 getDialog : function(){
2267 dlg = new Roo.bootstrap.Modal( {
2270 //constraintoviewport:false,
2272 //collapsible : false,
2277 //buttonAlign:"center",
2278 closeClick : function(){
2279 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2282 handleButton("cancel");
2287 dlg.on("hide", handleHide);
2289 //dlg.addKeyListener(27, handleEsc);
2291 this.buttons = buttons;
2292 var bt = this.buttonText;
2293 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2294 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2295 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2296 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2298 bodyEl = dlg.body.createChild({
2300 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2301 '<textarea class="roo-mb-textarea"></textarea>' +
2302 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2304 msgEl = bodyEl.dom.firstChild;
2305 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2306 textboxEl.enableDisplayMode();
2307 textboxEl.addKeyListener([10,13], function(){
2308 if(dlg.isVisible() && opt && opt.buttons){
2311 }else if(opt.buttons.yes){
2312 handleButton("yes");
2316 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2317 textareaEl.enableDisplayMode();
2318 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2319 progressEl.enableDisplayMode();
2320 var pf = progressEl.dom.firstChild;
2322 pp = Roo.get(pf.firstChild);
2323 pp.setHeight(pf.offsetHeight);
2331 * Updates the message box body text
2332 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2333 * the XHTML-compliant non-breaking space character '&#160;')
2334 * @return {Roo.MessageBox} This message box
2336 updateText : function(text){
2337 if(!dlg.isVisible() && !opt.width){
2338 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2340 msgEl.innerHTML = text || ' ';
2342 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2343 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2345 Math.min(opt.width || cw , this.maxWidth),
2346 Math.max(opt.minWidth || this.minWidth, bwidth)
2349 activeTextEl.setWidth(w);
2351 if(dlg.isVisible()){
2352 dlg.fixedcenter = false;
2354 // to big, make it scroll. = But as usual stupid IE does not support
2357 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2358 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2359 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2361 bodyEl.dom.style.height = '';
2362 bodyEl.dom.style.overflowY = '';
2365 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2367 bodyEl.dom.style.overflowX = '';
2370 dlg.setContentSize(w, bodyEl.getHeight());
2371 if(dlg.isVisible()){
2372 dlg.fixedcenter = true;
2378 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2379 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2380 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2381 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2382 * @return {Roo.MessageBox} This message box
2384 updateProgress : function(value, text){
2386 this.updateText(text);
2388 if (pp) { // weird bug on my firefox - for some reason this is not defined
2389 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2395 * Returns true if the message box is currently displayed
2396 * @return {Boolean} True if the message box is visible, else false
2398 isVisible : function(){
2399 return dlg && dlg.isVisible();
2403 * Hides the message box if it is displayed
2406 if(this.isVisible()){
2412 * Displays a new message box, or reinitializes an existing message box, based on the config options
2413 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2414 * The following config object properties are supported:
2416 Property Type Description
2417 ---------- --------------- ------------------------------------------------------------------------------------
2418 animEl String/Element An id or Element from which the message box should animate as it opens and
2419 closes (defaults to undefined)
2420 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2421 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2422 closable Boolean False to hide the top-right close button (defaults to true). Note that
2423 progress and wait dialogs will ignore this property and always hide the
2424 close button as they can only be closed programmatically.
2425 cls String A custom CSS class to apply to the message box element
2426 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2427 displayed (defaults to 75)
2428 fn Function A callback function to execute after closing the dialog. The arguments to the
2429 function will be btn (the name of the button that was clicked, if applicable,
2430 e.g. "ok"), and text (the value of the active text field, if applicable).
2431 Progress and wait dialogs will ignore this option since they do not respond to
2432 user actions and can only be closed programmatically, so any required function
2433 should be called by the same code after it closes the dialog.
2434 icon String A CSS class that provides a background image to be used as an icon for
2435 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2436 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2437 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2438 modal Boolean False to allow user interaction with the page while the message box is
2439 displayed (defaults to true)
2440 msg String A string that will replace the existing message box body text (defaults
2441 to the XHTML-compliant non-breaking space character ' ')
2442 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2443 progress Boolean True to display a progress bar (defaults to false)
2444 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2445 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2446 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2447 title String The title text
2448 value String The string value to set into the active textbox element if displayed
2449 wait Boolean True to display a progress bar (defaults to false)
2450 width Number The width of the dialog in pixels
2457 msg: 'Please enter your address:',
2459 buttons: Roo.MessageBox.OKCANCEL,
2462 animEl: 'addAddressBtn'
2465 * @param {Object} config Configuration options
2466 * @return {Roo.MessageBox} This message box
2468 show : function(options)
2471 // this causes nightmares if you show one dialog after another
2472 // especially on callbacks..
2474 if(this.isVisible()){
2477 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2478 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2479 Roo.log("New Dialog Message:" + options.msg )
2480 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2481 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2484 var d = this.getDialog();
2486 d.setTitle(opt.title || " ");
2487 d.close.setDisplayed(opt.closable !== false);
2488 activeTextEl = textboxEl;
2489 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2494 textareaEl.setHeight(typeof opt.multiline == "number" ?
2495 opt.multiline : this.defaultTextHeight);
2496 activeTextEl = textareaEl;
2505 progressEl.setDisplayed(opt.progress === true);
2506 this.updateProgress(0);
2507 activeTextEl.dom.value = opt.value || "";
2509 dlg.setDefaultButton(activeTextEl);
2511 var bs = opt.buttons;
2515 }else if(bs && bs.yes){
2516 db = buttons["yes"];
2518 dlg.setDefaultButton(db);
2520 bwidth = updateButtons(opt.buttons);
2521 this.updateText(opt.msg);
2523 d.el.addClass(opt.cls);
2525 d.proxyDrag = opt.proxyDrag === true;
2526 d.modal = opt.modal !== false;
2527 d.mask = opt.modal !== false ? mask : false;
2529 // force it to the end of the z-index stack so it gets a cursor in FF
2530 document.body.appendChild(dlg.el.dom);
2531 d.animateTarget = null;
2532 d.show(options.animEl);
2538 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2539 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2540 * and closing the message box when the process is complete.
2541 * @param {String} title The title bar text
2542 * @param {String} msg The message box body text
2543 * @return {Roo.MessageBox} This message box
2545 progress : function(title, msg){
2552 minWidth: this.minProgressWidth,
2559 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2560 * If a callback function is passed it will be called after the user clicks the button, and the
2561 * id of the button that was clicked will be passed as the only parameter to the callback
2562 * (could also be the top-right close button).
2563 * @param {String} title The title bar text
2564 * @param {String} msg The message box body text
2565 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2566 * @param {Object} scope (optional) The scope of the callback function
2567 * @return {Roo.MessageBox} This message box
2569 alert : function(title, msg, fn, scope){
2582 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2583 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2584 * You are responsible for closing the message box when the process is complete.
2585 * @param {String} msg The message box body text
2586 * @param {String} title (optional) The title bar text
2587 * @return {Roo.MessageBox} This message box
2589 wait : function(msg, title){
2600 waitTimer = Roo.TaskMgr.start({
2602 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2610 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2611 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2612 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2613 * @param {String} title The title bar text
2614 * @param {String} msg The message box body text
2615 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2616 * @param {Object} scope (optional) The scope of the callback function
2617 * @return {Roo.MessageBox} This message box
2619 confirm : function(title, msg, fn, scope){
2623 buttons: this.YESNO,
2632 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2633 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2634 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2635 * (could also be the top-right close button) and the text that was entered will be passed as the two
2636 * parameters to the callback.
2637 * @param {String} title The title bar text
2638 * @param {String} msg The message box body text
2639 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2640 * @param {Object} scope (optional) The scope of the callback function
2641 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2642 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2643 * @return {Roo.MessageBox} This message box
2645 prompt : function(title, msg, fn, scope, multiline){
2649 buttons: this.OKCANCEL,
2654 multiline: multiline,
2661 * Button config that displays a single OK button
2666 * Button config that displays Yes and No buttons
2669 YESNO : {yes:true, no:true},
2671 * Button config that displays OK and Cancel buttons
2674 OKCANCEL : {ok:true, cancel:true},
2676 * Button config that displays Yes, No and Cancel buttons
2679 YESNOCANCEL : {yes:true, no:true, cancel:true},
2682 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2685 defaultTextHeight : 75,
2687 * The maximum width in pixels of the message box (defaults to 600)
2692 * The minimum width in pixels of the message box (defaults to 100)
2697 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2698 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2701 minProgressWidth : 250,
2703 * An object containing the default button text strings that can be overriden for localized language support.
2704 * Supported properties are: ok, cancel, yes and no.
2705 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2718 * Shorthand for {@link Roo.MessageBox}
2720 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2721 Roo.Msg = Roo.Msg || Roo.MessageBox;
2730 * @class Roo.bootstrap.Navbar
2731 * @extends Roo.bootstrap.Component
2732 * Bootstrap Navbar class
2735 * Create a new Navbar
2736 * @param {Object} config The config object
2740 Roo.bootstrap.Navbar = function(config){
2741 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2745 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2754 getAutoCreate : function(){
2757 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
2761 initEvents :function ()
2763 //Roo.log(this.el.select('.navbar-toggle',true));
2764 this.el.select('.navbar-toggle',true).on('click', function() {
2765 // Roo.log('click');
2766 this.el.select('.navbar-collapse',true).toggleClass('in');
2774 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2776 var size = this.el.getSize();
2777 this.maskEl.setSize(size.width, size.height);
2778 this.maskEl.enableDisplayMode("block");
2787 getChildContainer : function()
2789 if (this.el.select('.collapse').getCount()) {
2790 return this.el.select('.collapse',true).first();
2822 * @class Roo.bootstrap.NavSimplebar
2823 * @extends Roo.bootstrap.Navbar
2824 * Bootstrap Sidebar class
2826 * @cfg {Boolean} inverse is inverted color
2828 * @cfg {String} type (nav | pills | tabs)
2829 * @cfg {Boolean} arrangement stacked | justified
2830 * @cfg {String} align (left | right) alignment
2832 * @cfg {Boolean} main (true|false) main nav bar? default false
2833 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
2835 * @cfg {String} tag (header|footer|nav|div) default is nav
2841 * Create a new Sidebar
2842 * @param {Object} config The config object
2846 Roo.bootstrap.NavSimplebar = function(config){
2847 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
2850 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
2866 getAutoCreate : function(){
2870 tag : this.tag || 'div',
2883 this.type = this.type || 'nav';
2884 if (['tabs','pills'].indexOf(this.type)!==-1) {
2885 cfg.cn[0].cls += ' nav-' + this.type
2889 if (this.type!=='nav') {
2890 Roo.log('nav type must be nav/tabs/pills')
2892 cfg.cn[0].cls += ' navbar-nav'
2898 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
2899 cfg.cn[0].cls += ' nav-' + this.arrangement;
2903 if (this.align === 'right') {
2904 cfg.cn[0].cls += ' navbar-right';
2908 cfg.cls += ' navbar-inverse';
2935 * @class Roo.bootstrap.NavHeaderbar
2936 * @extends Roo.bootstrap.NavSimplebar
2937 * Bootstrap Sidebar class
2939 * @cfg {String} brand what is brand
2940 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
2941 * @cfg {String} brand_href href of the brand
2944 * Create a new Sidebar
2945 * @param {Object} config The config object
2949 Roo.bootstrap.NavHeaderbar = function(config){
2950 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
2953 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
2960 getAutoCreate : function(){
2965 tag: this.nav || 'nav',
2971 cls: 'navbar-header',
2976 cls: 'navbar-toggle',
2977 'data-toggle': 'collapse',
2982 html: 'Toggle navigation'
3002 cls: 'collapse navbar-collapse'
3007 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3009 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3010 cfg.cls += ' navbar-' + this.position;
3012 // tag can override this..
3014 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3017 if (this.brand !== '') {
3020 href: this.brand_href ? this.brand_href : '#',
3021 cls: 'navbar-brand',
3029 cfg.cls += ' main-nav';
3054 * @class Roo.bootstrap.NavSidebar
3055 * @extends Roo.bootstrap.Navbar
3056 * Bootstrap Sidebar class
3059 * Create a new Sidebar
3060 * @param {Object} config The config object
3064 Roo.bootstrap.NavSidebar = function(config){
3065 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3068 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3070 sidebar : true, // used by Navbar Item at present...
3072 getAutoCreate : function(){
3077 cls: 'sidebar sidebar-nav'
3099 * @class Roo.bootstrap.NavGroup
3100 * @extends Roo.bootstrap.Component
3101 * Bootstrap NavGroup class
3102 * @cfg {String} align left | right
3103 * @cfg {Boolean} inverse false | true
3104 * @cfg {String} type (nav|pills|tab) default nav
3105 * @cfg {String} navId - reference Id for navbar.
3109 * Create a new nav group
3110 * @param {Object} config The config object
3113 Roo.bootstrap.NavGroup = function(config){
3114 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3116 Roo.bootstrap.NavGroup.register(this);
3120 * Fires when the active item changes
3121 * @param {Roo.bootstrap.NavGroup} this
3122 * @param {Roo.bootstrap.Navbar.Item} item The item selected
3123 * @param {Roo.bootstrap.Navbar.Item} item The previously selected item
3130 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3141 getAutoCreate : function()
3143 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3150 if (['tabs','pills'].indexOf(this.type)!==-1) {
3151 cfg.cls += ' nav-' + this.type
3153 if (this.type!=='nav') {
3154 Roo.log('nav type must be nav/tabs/pills')
3156 cfg.cls += ' navbar-nav'
3159 if (this.parent() instanceof Roo.bootstrap.NavSidebar) {
3162 cls: 'dashboard-menu'
3168 if (this.form === true) {
3174 if (this.align === 'right') {
3175 cfg.cls += ' navbar-right';
3177 cfg.cls += ' navbar-left';
3181 if (this.align === 'right') {
3182 cfg.cls += ' navbar-right';
3186 cfg.cls += ' navbar-inverse';
3194 setActiveItem : function(item)
3197 Roo.each(this.navItems, function(v){
3202 v.setActive(false, true);
3209 item.setActive(true, true);
3210 this.fireEvent('changed', this, item, prev);
3216 register : function(item)
3218 this.navItems.push( item);
3219 item.navId = this.navId;
3222 getNavItem: function(tabId)
3225 Roo.each(this.navItems, function(e) {
3226 if (e.tabId == tabId) {
3238 Roo.apply(Roo.bootstrap.NavGroup, {
3242 register : function(navgrp)
3244 this.groups[navgrp.navId] = navgrp;
3247 get: function(navId) {
3248 return this.groups[navId];
3263 * @class Roo.bootstrap.Navbar.Item
3264 * @extends Roo.bootstrap.Component
3265 * Bootstrap Navbar.Button class
3266 * @cfg {String} href link to
3267 * @cfg {String} html content of button
3268 * @cfg {String} badge text inside badge
3269 * @cfg {String} glyphicon name of glyphicon
3270 * @cfg {String} icon name of font awesome icon
3271 * @cfg {Boolean} active Is item active
3272 * @cfg {Boolean} preventDefault (true | false) default false
3273 * @cfg {String} tabId the tab that this item activates.
3276 * Create a new Navbar Button
3277 * @param {Object} config The config object
3279 Roo.bootstrap.Navbar.Item = function(config){
3280 Roo.bootstrap.Navbar.Item.superclass.constructor.call(this, config);
3285 * The raw click event for the entire grid.
3286 * @param {Roo.EventObject} e
3291 * Fires when the active item active state changes
3292 * @param {Roo.bootstrap.Navbar.Item} this
3293 * @param {boolean} state the new state
3301 Roo.extend(Roo.bootstrap.Navbar.Item, Roo.bootstrap.Component, {
3309 preventDefault : false,
3312 getAutoCreate : function(){
3314 var cfg = Roo.apply({}, Roo.bootstrap.Navbar.Item.superclass.getAutoCreate.call(this));
3316 if (this.parent().parent().sidebar === true) {
3329 cfg.cn[0].html = this.html;
3333 this.cls += ' active';
3337 cfg.cn[0].cls += ' dropdown-toggle';
3338 cfg.cn[0].html = (cfg.cn[0].html || this.html) + '<span class="glyphicon glyphicon-chevron-down"></span>';
3342 cfg.cn[0].tag = 'a',
3343 cfg.cn[0].href = this.href;
3346 if (this.glyphicon) {
3347 cfg.cn[0].html = '<i class="glyphicon glyphicon-'+this.glyphicon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
3351 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
3363 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3373 if (this.glyphicon) {
3374 if(cfg.html){cfg.html = ' ' + this.html};
3378 cls: 'glyphicon glyphicon-' + this.glyphicon
3383 cfg.cn[0].html = this.html || cfg.cn[0].html ;
3388 cfg.cn[0].html += " <span class='caret'></span>";
3389 //}else if (!this.href) {
3390 // cfg.cn[0].tag='p';
3391 // cfg.cn[0].cls='navbar-text';
3394 cfg.cn[0].href=this.href||'#';
3395 cfg.cn[0].html=this.html;
3398 if (this.badge !== '') {
3401 cfg.cn[0].html + ' ',
3412 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
3417 initEvents: function() {
3418 // Roo.log('init events?');
3419 // Roo.log(this.el.dom);
3420 this.el.select('a',true).on('click', this.onClick, this);
3421 // at this point parent should be available..
3422 this.parent().register(this);
3425 onClick : function(e)
3427 if(this.preventDefault){
3431 if(this.fireEvent('click', this, e) === false){
3435 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3436 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3437 this.parent().setActiveItem(this);
3445 isActive: function () {
3448 setActive : function(state, fire)
3450 this.active = state;
3452 this.el.removeClass('active');
3453 } else if (!this.el.hasClass('active')) {
3454 this.el.addClass('active');
3457 this.fireEvent('changed', this, state);
3462 // this should not be here...
3475 * @class Roo.bootstrap.Row
3476 * @extends Roo.bootstrap.Component
3477 * Bootstrap Row class (contains columns...)
3481 * @param {Object} config The config object
3484 Roo.bootstrap.Row = function(config){
3485 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3488 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3490 getAutoCreate : function(){
3509 * @class Roo.bootstrap.Element
3510 * @extends Roo.bootstrap.Component
3511 * Bootstrap Element class
3512 * @cfg {String} html contents of the element
3513 * @cfg {String} tag tag of the element
3514 * @cfg {String} cls class of the element
3517 * Create a new Element
3518 * @param {Object} config The config object
3521 Roo.bootstrap.Element = function(config){
3522 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3525 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3532 getAutoCreate : function(){
3557 * @class Roo.bootstrap.Pagination
3558 * @extends Roo.bootstrap.Component
3559 * Bootstrap Pagination class
3560 * @cfg {String} size xs | sm | md | lg
3561 * @cfg {Boolean} inverse false | true
3564 * Create a new Pagination
3565 * @param {Object} config The config object
3568 Roo.bootstrap.Pagination = function(config){
3569 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3572 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3578 getAutoCreate : function(){
3584 cfg.cls += ' inverse';
3590 cfg.cls += " " + this.cls;
3608 * @class Roo.bootstrap.PaginationItem
3609 * @extends Roo.bootstrap.Component
3610 * Bootstrap PaginationItem class
3611 * @cfg {String} html text
3612 * @cfg {String} href the link
3613 * @cfg {Boolean} preventDefault (true | false) default true
3614 * @cfg {Boolean} active (true | false) default false
3618 * Create a new PaginationItem
3619 * @param {Object} config The config object
3623 Roo.bootstrap.PaginationItem = function(config){
3624 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3629 * The raw click event for the entire grid.
3630 * @param {Roo.EventObject} e
3636 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
3640 preventDefault: true,
3644 getAutoCreate : function(){
3650 href : this.href ? this.href : '#',
3651 html : this.html ? this.html : ''
3661 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
3667 initEvents: function() {
3669 this.el.on('click', this.onClick, this);
3672 onClick : function(e)
3674 Roo.log('PaginationItem on click ');
3675 if(this.preventDefault){
3679 this.fireEvent('click', this, e);
3695 * @class Roo.bootstrap.Slider
3696 * @extends Roo.bootstrap.Component
3697 * Bootstrap Slider class
3700 * Create a new Slider
3701 * @param {Object} config The config object
3704 Roo.bootstrap.Slider = function(config){
3705 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
3708 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
3710 getAutoCreate : function(){
3714 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
3718 cls: 'ui-slider-handle ui-state-default ui-corner-all'
3736 * @class Roo.bootstrap.Table
3737 * @extends Roo.bootstrap.Component
3738 * Bootstrap Table class
3739 * @cfg {String} cls table class
3740 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
3741 * @cfg {String} bgcolor Specifies the background color for a table
3742 * @cfg {Number} border Specifies whether the table cells should have borders or not
3743 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
3744 * @cfg {Number} cellspacing Specifies the space between cells
3745 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
3746 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
3747 * @cfg {String} sortable Specifies that the table should be sortable
3748 * @cfg {String} summary Specifies a summary of the content of a table
3749 * @cfg {Number} width Specifies the width of a table
3751 * @cfg {boolean} striped Should the rows be alternative striped
3752 * @cfg {boolean} bordered Add borders to the table
3753 * @cfg {boolean} hover Add hover highlighting
3754 * @cfg {boolean} condensed Format condensed
3755 * @cfg {boolean} responsive Format condensed
3761 * Create a new Table
3762 * @param {Object} config The config object
3765 Roo.bootstrap.Table = function(config){
3766 Roo.bootstrap.Table.superclass.constructor.call(this, config);
3769 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
3770 this.sm = this.selModel;
3771 this.sm.xmodule = this.xmodule || false;
3773 if (this.cm && typeof(this.cm.config) == 'undefined') {
3774 this.colModel = new Roo.bootstrap.Table.ColumnModel(this.cm);
3775 this.cm = this.colModel;
3776 this.cm.xmodule = this.xmodule || false;
3779 this.store= Roo.factory(this.store, Roo.data);
3780 this.ds = this.store;
3781 this.ds.xmodule = this.xmodule || false;
3786 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
3808 getAutoCreate : function(){
3809 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
3818 cfg.cls += ' table-striped';
3821 cfg.cls += ' table-hover';
3823 if (this.bordered) {
3824 cfg.cls += ' table-bordered';
3826 if (this.condensed) {
3827 cfg.cls += ' table-condensed';
3829 if (this.responsive) {
3830 cfg.cls += ' table-responsive';
3837 cfg.cls+= ' ' +this.cls;
3840 // this lot should be simplifed...
3843 cfg.align=this.align;
3846 cfg.bgcolor=this.bgcolor;
3849 cfg.border=this.border;
3851 if (this.cellpadding) {
3852 cfg.cellpadding=this.cellpadding;
3854 if (this.cellspacing) {
3855 cfg.cellspacing=this.cellspacing;
3858 cfg.frame=this.frame;
3861 cfg.rules=this.rules;
3863 if (this.sortable) {
3864 cfg.sortable=this.sortable;
3867 cfg.summary=this.summary;
3870 cfg.width=this.width;
3873 if(this.store || this.cm){
3874 cfg.cn.push(this.renderHeader());
3875 cfg.cn.push(this.renderBody());
3876 cfg.cn.push(this.renderFooter());
3878 cfg.cls+= ' TableGrid';
3884 // initTableGrid : function()
3893 // var cm = this.cm;
3895 // for(var i = 0, len = cm.getColumnCount(); i < len; i++){
3898 // html: cm.getColumnHeader(i)
3902 // cfg.push(header);
3909 initEvents : function()
3911 if(!this.store || !this.cm){
3915 Roo.log('initEvents with ds!!!!');
3919 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
3920 e.on('click', _this.sort, _this);
3922 // this.maskEl = Roo.DomHelper.append(this.el.select('.TableGrid', true).first(), {tag: "div", cls:"x-dlg-mask"}, true);
3923 // this.maskEl.enableDisplayMode("block");
3924 // this.maskEl.show();
3926 this.store.on('load', this.onLoad, this);
3927 this.store.on('beforeload', this.onBeforeLoad, this);
3935 sort : function(e,el)
3937 var col = Roo.get(el)
3939 if(!col.hasClass('sortable')){
3943 var sort = col.attr('sort');
3946 if(col.hasClass('glyphicon-arrow-up')){
3950 this.store.sortInfo = {field : sort, direction : dir};
3955 renderHeader : function()
3964 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
3966 var config = cm.config[i];
3970 html: cm.getColumnHeader(i)
3973 if(typeof(config.dataIndex) != 'undefined'){
3974 c.sort = config.dataIndex;
3977 if(typeof(config.sortable) != 'undefined' && config.sortable){
3981 if(typeof(config.width) != 'undefined'){
3982 c.style = 'width:' + config.width + 'px';
3991 renderBody : function()
4001 renderFooter : function()
4013 Roo.log('ds onload');
4018 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4019 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
4021 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
4022 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
4025 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
4026 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
4030 var tbody = this.el.select('tbody', true).first();
4034 if(this.store.getCount() > 0){
4035 this.store.data.each(function(d){
4041 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4042 var renderer = cm.getRenderer(i);
4043 var config = cm.config[i];
4047 if(typeof(renderer) !== 'undefined'){
4048 value = renderer(d.data[cm.getDataIndex(i)], false, d);
4051 if(typeof(value) === 'object'){
4061 html: (typeof(value) === 'object') ? '' : value
4064 if(typeof(config.width) != 'undefined'){
4065 td.style = 'width:' + config.width + 'px';
4072 tbody.createChild(row);
4080 Roo.each(renders, function(r){
4081 _this.renderColumn(r);
4085 // if(this.loadMask){
4086 // this.maskEl.hide();
4090 onBeforeLoad : function()
4092 Roo.log('ds onBeforeLoad');
4096 // if(this.loadMask){
4097 // this.maskEl.show();
4103 this.el.select('tbody', true).first().dom.innerHTML = '';
4106 getSelectionModel : function(){
4108 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
4110 return this.selModel;
4113 renderColumn : function(r)
4116 r.cfg.render(Roo.get(r.id));
4119 Roo.each(r.cfg.cn, function(c){
4124 _this.renderColumn(child);
4141 * @class Roo.bootstrap.TableCell
4142 * @extends Roo.bootstrap.Component
4143 * Bootstrap TableCell class
4144 * @cfg {String} html cell contain text
4145 * @cfg {String} cls cell class
4146 * @cfg {String} tag cell tag (td|th) default td
4147 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
4148 * @cfg {String} align Aligns the content in a cell
4149 * @cfg {String} axis Categorizes cells
4150 * @cfg {String} bgcolor Specifies the background color of a cell
4151 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
4152 * @cfg {Number} colspan Specifies the number of columns a cell should span
4153 * @cfg {String} headers Specifies one or more header cells a cell is related to
4154 * @cfg {Number} height Sets the height of a cell
4155 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
4156 * @cfg {Number} rowspan Sets the number of rows a cell should span
4157 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
4158 * @cfg {String} valign Vertical aligns the content in a cell
4159 * @cfg {Number} width Specifies the width of a cell
4162 * Create a new TableCell
4163 * @param {Object} config The config object
4166 Roo.bootstrap.TableCell = function(config){
4167 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
4170 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
4190 getAutoCreate : function(){
4191 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
4211 cfg.align=this.align
4217 cfg.bgcolor=this.bgcolor
4220 cfg.charoff=this.charoff
4223 cfg.colspan=this.colspan
4226 cfg.headers=this.headers
4229 cfg.height=this.height
4232 cfg.nowrap=this.nowrap
4235 cfg.rowspan=this.rowspan
4238 cfg.scope=this.scope
4241 cfg.valign=this.valign
4244 cfg.width=this.width
4263 * @class Roo.bootstrap.TableRow
4264 * @extends Roo.bootstrap.Component
4265 * Bootstrap TableRow class
4266 * @cfg {String} cls row class
4267 * @cfg {String} align Aligns the content in a table row
4268 * @cfg {String} bgcolor Specifies a background color for a table row
4269 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
4270 * @cfg {String} valign Vertical aligns the content in a table row
4273 * Create a new TableRow
4274 * @param {Object} config The config object
4277 Roo.bootstrap.TableRow = function(config){
4278 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
4281 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
4289 getAutoCreate : function(){
4290 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
4300 cfg.align = this.align;
4303 cfg.bgcolor = this.bgcolor;
4306 cfg.charoff = this.charoff;
4309 cfg.valign = this.valign;
4327 * @class Roo.bootstrap.TableBody
4328 * @extends Roo.bootstrap.Component
4329 * Bootstrap TableBody class
4330 * @cfg {String} cls element class
4331 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
4332 * @cfg {String} align Aligns the content inside the element
4333 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
4334 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
4337 * Create a new TableBody
4338 * @param {Object} config The config object
4341 Roo.bootstrap.TableBody = function(config){
4342 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
4345 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
4353 getAutoCreate : function(){
4354 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
4368 cfg.align = this.align;
4371 cfg.charoff = this.charoff;
4374 cfg.valign = this.valign;
4381 // initEvents : function()
4388 // this.store = Roo.factory(this.store, Roo.data);
4389 // this.store.on('load', this.onLoad, this);
4391 // this.store.load();
4395 // onLoad: function ()
4397 // this.fireEvent('load', this);
4407 * Ext JS Library 1.1.1
4408 * Copyright(c) 2006-2007, Ext JS, LLC.
4410 * Originally Released Under LGPL - original licence link has changed is not relivant.
4413 * <script type="text/javascript">
4416 // as we use this in bootstrap.
4417 Roo.namespace('Roo.form');
4419 * @class Roo.form.Action
4420 * Internal Class used to handle form actions
4422 * @param {Roo.form.BasicForm} el The form element or its id
4423 * @param {Object} config Configuration options
4428 // define the action interface
4429 Roo.form.Action = function(form, options){
4431 this.options = options || {};
4434 * Client Validation Failed
4437 Roo.form.Action.CLIENT_INVALID = 'client';
4439 * Server Validation Failed
4442 Roo.form.Action.SERVER_INVALID = 'server';
4444 * Connect to Server Failed
4447 Roo.form.Action.CONNECT_FAILURE = 'connect';
4449 * Reading Data from Server Failed
4452 Roo.form.Action.LOAD_FAILURE = 'load';
4454 Roo.form.Action.prototype = {
4456 failureType : undefined,
4457 response : undefined,
4461 run : function(options){
4466 success : function(response){
4471 handleResponse : function(response){
4475 // default connection failure
4476 failure : function(response){
4478 this.response = response;
4479 this.failureType = Roo.form.Action.CONNECT_FAILURE;
4480 this.form.afterAction(this, false);
4483 processResponse : function(response){
4484 this.response = response;
4485 if(!response.responseText){
4488 this.result = this.handleResponse(response);
4492 // utility functions used internally
4493 getUrl : function(appendParams){
4494 var url = this.options.url || this.form.url || this.form.el.dom.action;
4496 var p = this.getParams();
4498 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
4504 getMethod : function(){
4505 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
4508 getParams : function(){
4509 var bp = this.form.baseParams;
4510 var p = this.options.params;
4512 if(typeof p == "object"){
4513 p = Roo.urlEncode(Roo.applyIf(p, bp));
4514 }else if(typeof p == 'string' && bp){
4515 p += '&' + Roo.urlEncode(bp);
4518 p = Roo.urlEncode(bp);
4523 createCallback : function(){
4525 success: this.success,
4526 failure: this.failure,
4528 timeout: (this.form.timeout*1000),
4529 upload: this.form.fileUpload ? this.success : undefined
4534 Roo.form.Action.Submit = function(form, options){
4535 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
4538 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
4541 haveProgress : false,
4542 uploadComplete : false,
4544 // uploadProgress indicator.
4545 uploadProgress : function()
4547 if (!this.form.progressUrl) {
4551 if (!this.haveProgress) {
4552 Roo.MessageBox.progress("Uploading", "Uploading");
4554 if (this.uploadComplete) {
4555 Roo.MessageBox.hide();
4559 this.haveProgress = true;
4561 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
4563 var c = new Roo.data.Connection();
4565 url : this.form.progressUrl,
4570 success : function(req){
4571 //console.log(data);
4575 rdata = Roo.decode(req.responseText)
4577 Roo.log("Invalid data from server..");
4581 if (!rdata || !rdata.success) {
4583 Roo.MessageBox.alert(Roo.encode(rdata));
4586 var data = rdata.data;
4588 if (this.uploadComplete) {
4589 Roo.MessageBox.hide();
4594 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
4595 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
4598 this.uploadProgress.defer(2000,this);
4601 failure: function(data) {
4602 Roo.log('progress url failed ');
4613 // run get Values on the form, so it syncs any secondary forms.
4614 this.form.getValues();
4616 var o = this.options;
4617 var method = this.getMethod();
4618 var isPost = method == 'POST';
4619 if(o.clientValidation === false || this.form.isValid()){
4621 if (this.form.progressUrl) {
4622 this.form.findField('UPLOAD_IDENTIFIER').setValue(
4623 (new Date() * 1) + '' + Math.random());
4628 Roo.Ajax.request(Roo.apply(this.createCallback(), {
4629 form:this.form.el.dom,
4630 url:this.getUrl(!isPost),
4632 params:isPost ? this.getParams() : null,
4633 isUpload: this.form.fileUpload
4636 this.uploadProgress();
4638 }else if (o.clientValidation !== false){ // client validation failed
4639 this.failureType = Roo.form.Action.CLIENT_INVALID;
4640 this.form.afterAction(this, false);
4644 success : function(response)
4646 this.uploadComplete= true;
4647 if (this.haveProgress) {
4648 Roo.MessageBox.hide();
4652 var result = this.processResponse(response);
4653 if(result === true || result.success){
4654 this.form.afterAction(this, true);
4658 this.form.markInvalid(result.errors);
4659 this.failureType = Roo.form.Action.SERVER_INVALID;
4661 this.form.afterAction(this, false);
4663 failure : function(response)
4665 this.uploadComplete= true;
4666 if (this.haveProgress) {
4667 Roo.MessageBox.hide();
4670 this.response = response;
4671 this.failureType = Roo.form.Action.CONNECT_FAILURE;
4672 this.form.afterAction(this, false);
4675 handleResponse : function(response){
4676 if(this.form.errorReader){
4677 var rs = this.form.errorReader.read(response);
4680 for(var i = 0, len = rs.records.length; i < len; i++) {
4681 var r = rs.records[i];
4685 if(errors.length < 1){
4689 success : rs.success,
4695 ret = Roo.decode(response.responseText);
4699 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
4709 Roo.form.Action.Load = function(form, options){
4710 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
4711 this.reader = this.form.reader;
4714 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
4719 Roo.Ajax.request(Roo.apply(
4720 this.createCallback(), {
4721 method:this.getMethod(),
4722 url:this.getUrl(false),
4723 params:this.getParams()
4727 success : function(response){
4729 var result = this.processResponse(response);
4730 if(result === true || !result.success || !result.data){
4731 this.failureType = Roo.form.Action.LOAD_FAILURE;
4732 this.form.afterAction(this, false);
4735 this.form.clearInvalid();
4736 this.form.setValues(result.data);
4737 this.form.afterAction(this, true);
4740 handleResponse : function(response){
4741 if(this.form.reader){
4742 var rs = this.form.reader.read(response);
4743 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
4745 success : rs.success,
4749 return Roo.decode(response.responseText);
4753 Roo.form.Action.ACTION_TYPES = {
4754 'load' : Roo.form.Action.Load,
4755 'submit' : Roo.form.Action.Submit
4764 * @class Roo.bootstrap.Form
4765 * @extends Roo.bootstrap.Component
4766 * Bootstrap Form class
4767 * @cfg {String} method GET | POST (default POST)
4768 * @cfg {String} labelAlign top | left (default top)
4769 * @cfg {String} align left | right - for navbars
4774 * @param {Object} config The config object
4778 Roo.bootstrap.Form = function(config){
4779 Roo.bootstrap.Form.superclass.constructor.call(this, config);
4782 * @event clientvalidation
4783 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
4784 * @param {Form} this
4785 * @param {Boolean} valid true if the form has passed client-side validation
4787 clientvalidation: true,
4789 * @event beforeaction
4790 * Fires before any action is performed. Return false to cancel the action.
4791 * @param {Form} this
4792 * @param {Action} action The action to be performed
4796 * @event actionfailed
4797 * Fires when an action fails.
4798 * @param {Form} this
4799 * @param {Action} action The action that failed
4801 actionfailed : true,
4803 * @event actioncomplete
4804 * Fires when an action is completed.
4805 * @param {Form} this
4806 * @param {Action} action The action that completed
4808 actioncomplete : true
4813 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
4816 * @cfg {String} method
4817 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
4822 * The URL to use for form actions if one isn't supplied in the action options.
4825 * @cfg {Boolean} fileUpload
4826 * Set to true if this form is a file upload.
4830 * @cfg {Object} baseParams
4831 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
4835 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
4839 * @cfg {Sting} align (left|right) for navbar forms
4844 activeAction : null,
4847 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
4848 * element by passing it or its id or mask the form itself by passing in true.
4851 waitMsgTarget : false,
4856 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
4857 * element by passing it or its id or mask the form itself by passing in true.
4861 getAutoCreate : function(){
4865 method : this.method || 'POST',
4866 id : this.id || Roo.id(),
4869 if (this.parent().xtype.match(/^Nav/)) {
4870 cfg.cls = 'navbar-form navbar-' + this.align;
4874 if (this.labelAlign == 'left' ) {
4875 cfg.cls += ' form-horizontal';
4881 initEvents : function()
4883 this.el.on('submit', this.onSubmit, this);
4888 onSubmit : function(e){
4893 * Returns true if client-side validation on the form is successful.
4896 isValid : function(){
4897 var items = this.getItems();
4899 items.each(function(f){
4908 * Returns true if any fields in this form have changed since their original load.
4911 isDirty : function(){
4913 var items = this.getItems();
4914 items.each(function(f){
4924 * Performs a predefined action (submit or load) or custom actions you define on this form.
4925 * @param {String} actionName The name of the action type
4926 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
4927 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
4928 * accept other config options):
4930 Property Type Description
4931 ---------------- --------------- ----------------------------------------------------------------------------------
4932 url String The url for the action (defaults to the form's url)
4933 method String The form method to use (defaults to the form's method, or POST if not defined)
4934 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
4935 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
4936 validate the form on the client (defaults to false)
4938 * @return {BasicForm} this
4940 doAction : function(action, options){
4941 if(typeof action == 'string'){
4942 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
4944 if(this.fireEvent('beforeaction', this, action) !== false){
4945 this.beforeAction(action);
4946 action.run.defer(100, action);
4952 beforeAction : function(action){
4953 var o = action.options;
4955 // not really supported yet.. ??
4957 //if(this.waitMsgTarget === true){
4958 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
4959 //}else if(this.waitMsgTarget){
4960 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
4961 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
4963 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
4969 afterAction : function(action, success){
4970 this.activeAction = null;
4971 var o = action.options;
4973 //if(this.waitMsgTarget === true){
4975 //}else if(this.waitMsgTarget){
4976 // this.waitMsgTarget.unmask();
4978 // Roo.MessageBox.updateProgress(1);
4979 // Roo.MessageBox.hide();
4986 Roo.callback(o.success, o.scope, [this, action]);
4987 this.fireEvent('actioncomplete', this, action);
4991 // failure condition..
4992 // we have a scenario where updates need confirming.
4993 // eg. if a locking scenario exists..
4994 // we look for { errors : { needs_confirm : true }} in the response.
4996 (typeof(action.result) != 'undefined') &&
4997 (typeof(action.result.errors) != 'undefined') &&
4998 (typeof(action.result.errors.needs_confirm) != 'undefined')
5001 Roo.log("not supported yet");
5004 Roo.MessageBox.confirm(
5005 "Change requires confirmation",
5006 action.result.errorMsg,
5011 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
5021 Roo.callback(o.failure, o.scope, [this, action]);
5022 // show an error message if no failed handler is set..
5023 if (!this.hasListener('actionfailed')) {
5024 Roo.log("need to add dialog support");
5026 Roo.MessageBox.alert("Error",
5027 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
5028 action.result.errorMsg :
5029 "Saving Failed, please check your entries or try again"
5034 this.fireEvent('actionfailed', this, action);
5039 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
5040 * @param {String} id The value to search for
5043 findField : function(id){
5044 var items = this.getItems();
5045 var field = items.get(id);
5047 items.each(function(f){
5048 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
5055 return field || null;
5058 * Mark fields in this form invalid in bulk.
5059 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
5060 * @return {BasicForm} this
5062 markInvalid : function(errors){
5063 if(errors instanceof Array){
5064 for(var i = 0, len = errors.length; i < len; i++){
5065 var fieldError = errors[i];
5066 var f = this.findField(fieldError.id);
5068 f.markInvalid(fieldError.msg);
5074 if(typeof errors[id] != 'function' && (field = this.findField(id))){
5075 field.markInvalid(errors[id]);
5079 //Roo.each(this.childForms || [], function (f) {
5080 // f.markInvalid(errors);
5087 * Set values for fields in this form in bulk.
5088 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
5089 * @return {BasicForm} this
5091 setValues : function(values){
5092 if(values instanceof Array){ // array of objects
5093 for(var i = 0, len = values.length; i < len; i++){
5095 var f = this.findField(v.id);
5097 f.setValue(v.value);
5098 if(this.trackResetOnLoad){
5099 f.originalValue = f.getValue();
5103 }else{ // object hash
5106 if(typeof values[id] != 'function' && (field = this.findField(id))){
5108 if (field.setFromData &&
5110 field.displayField &&
5111 // combos' with local stores can
5112 // be queried via setValue()
5113 // to set their value..
5114 (field.store && !field.store.isLocal)
5118 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
5119 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
5120 field.setFromData(sd);
5123 field.setValue(values[id]);
5127 if(this.trackResetOnLoad){
5128 field.originalValue = field.getValue();
5134 //Roo.each(this.childForms || [], function (f) {
5135 // f.setValues(values);
5142 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
5143 * they are returned as an array.
5144 * @param {Boolean} asString
5147 getValues : function(asString){
5148 //if (this.childForms) {
5149 // copy values from the child forms
5150 // Roo.each(this.childForms, function (f) {
5151 // this.setValues(f.getValues());
5157 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
5158 if(asString === true){
5161 return Roo.urlDecode(fs);
5165 * Returns the fields in this form as an object with key/value pairs.
5166 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
5169 getFieldValues : function(with_hidden)
5171 var items = this.getItems();
5173 items.each(function(f){
5177 var v = f.getValue();
5178 if (f.inputType =='radio') {
5179 if (typeof(ret[f.getName()]) == 'undefined') {
5180 ret[f.getName()] = ''; // empty..
5183 if (!f.el.dom.checked) {
5191 // not sure if this supported any more..
5192 if ((typeof(v) == 'object') && f.getRawValue) {
5193 v = f.getRawValue() ; // dates..
5195 // combo boxes where name != hiddenName...
5196 if (f.name != f.getName()) {
5197 ret[f.name] = f.getRawValue();
5199 ret[f.getName()] = v;
5206 * Clears all invalid messages in this form.
5207 * @return {BasicForm} this
5209 clearInvalid : function(){
5210 var items = this.getItems();
5212 items.each(function(f){
5223 * @return {BasicForm} this
5226 var items = this.getItems();
5227 items.each(function(f){
5231 Roo.each(this.childForms || [], function (f) {
5238 getItems : function()
5240 var r=new Roo.util.MixedCollection(false, function(o){
5241 return o.id || (o.id = Roo.id());
5243 var iter = function(el) {
5250 Roo.each(el.items,function(e) {
5269 * Ext JS Library 1.1.1
5270 * Copyright(c) 2006-2007, Ext JS, LLC.
5272 * Originally Released Under LGPL - original licence link has changed is not relivant.
5275 * <script type="text/javascript">
5278 * @class Roo.form.VTypes
5279 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
5282 Roo.form.VTypes = function(){
5283 // closure these in so they are only created once.
5284 var alpha = /^[a-zA-Z_]+$/;
5285 var alphanum = /^[a-zA-Z0-9_]+$/;
5286 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
5287 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
5289 // All these messages and functions are configurable
5292 * The function used to validate email addresses
5293 * @param {String} value The email address
5295 'email' : function(v){
5296 return email.test(v);
5299 * The error text to display when the email validation function returns false
5302 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
5304 * The keystroke filter mask to be applied on email input
5307 'emailMask' : /[a-z0-9_\.\-@]/i,
5310 * The function used to validate URLs
5311 * @param {String} value The URL
5313 'url' : function(v){
5317 * The error text to display when the url validation function returns false
5320 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
5323 * The function used to validate alpha values
5324 * @param {String} value The value
5326 'alpha' : function(v){
5327 return alpha.test(v);
5330 * The error text to display when the alpha validation function returns false
5333 'alphaText' : 'This field should only contain letters and _',
5335 * The keystroke filter mask to be applied on alpha input
5338 'alphaMask' : /[a-z_]/i,
5341 * The function used to validate alphanumeric values
5342 * @param {String} value The value
5344 'alphanum' : function(v){
5345 return alphanum.test(v);
5348 * The error text to display when the alphanumeric validation function returns false
5351 'alphanumText' : 'This field should only contain letters, numbers and _',
5353 * The keystroke filter mask to be applied on alphanumeric input
5356 'alphanumMask' : /[a-z0-9_]/i
5366 * @class Roo.bootstrap.Input
5367 * @extends Roo.bootstrap.Component
5368 * Bootstrap Input class
5369 * @cfg {Boolean} disabled is it disabled
5370 * @cfg {String} fieldLabel - the label associated
5371 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
5372 * @cfg {String} name name of the input
5373 * @cfg {string} fieldLabel - the label associated
5374 * @cfg {string} inputType - input / file submit ...
5375 * @cfg {string} placeholder - placeholder to put in text.
5376 * @cfg {string} before - input group add on before
5377 * @cfg {string} after - input group add on after
5378 * @cfg {string} size - (lg|sm) or leave empty..
5379 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
5380 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
5381 * @cfg {Number} md colspan out of 12 for computer-sized screens
5382 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
5383 * @cfg {string} value default value of the input
5384 * @cfg {Number} labelWidth set the width of label (0-12)
5385 * @cfg {String} labelAlign (top|left)
5386 * @cfg {Boolean} readOnly Specifies that the field should be read-only
5390 * Create a new Input
5391 * @param {Object} config The config object
5394 Roo.bootstrap.Input = function(config){
5395 Roo.bootstrap.Input.superclass.constructor.call(this, config);
5400 * Fires when this field receives input focus.
5401 * @param {Roo.form.Field} this
5406 * Fires when this field loses input focus.
5407 * @param {Roo.form.Field} this
5412 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
5413 * {@link Roo.EventObject#getKey} to determine which key was pressed.
5414 * @param {Roo.form.Field} this
5415 * @param {Roo.EventObject} e The event object
5420 * Fires just before the field blurs if the field value has changed.
5421 * @param {Roo.form.Field} this
5422 * @param {Mixed} newValue The new value
5423 * @param {Mixed} oldValue The original value
5428 * Fires after the field has been marked as invalid.
5429 * @param {Roo.form.Field} this
5430 * @param {String} msg The validation message
5435 * Fires after the field has been validated with no errors.
5436 * @param {Roo.form.Field} this
5441 * Fires after the key up
5442 * @param {Roo.form.Field} this
5443 * @param {Roo.EventObject} e The event Object
5449 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
5451 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
5452 automatic validation (defaults to "keyup").
5454 validationEvent : "keyup",
5456 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
5458 validateOnBlur : true,
5460 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
5462 validationDelay : 250,
5464 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
5466 focusClass : "x-form-focus", // not needed???
5470 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
5472 invalidClass : "has-error",
5475 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
5477 selectOnFocus : false,
5480 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
5484 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
5489 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
5491 disableKeyFilter : false,
5494 * @cfg {Boolean} disabled True to disable the field (defaults to false).
5498 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
5502 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
5504 blankText : "This field is required",
5507 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
5511 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
5513 maxLength : Number.MAX_VALUE,
5515 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
5517 minLengthText : "The minimum length for this field is {0}",
5519 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
5521 maxLengthText : "The maximum length for this field is {0}",
5525 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
5526 * If available, this function will be called only after the basic validators all return true, and will be passed the
5527 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
5531 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
5532 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
5533 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
5537 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
5560 parentLabelAlign : function()
5563 while (parent.parent()) {
5564 parent = parent.parent();
5565 if (typeof(parent.labelAlign) !='undefined') {
5566 return parent.labelAlign;
5573 getAutoCreate : function(){
5575 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
5581 if(this.inputType != 'hidden'){
5582 cfg.cls = 'form-group' //input-group
5588 type : this.inputType,
5590 cls : 'form-control',
5591 placeholder : this.placeholder || ''
5595 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
5596 input.maxLength = this.maxLength;
5599 if (this.disabled) {
5600 input.disabled=true;
5603 if (this.readOnly) {
5604 input.readonly=true;
5608 input.name = this.name;
5611 input.cls += ' input-' + this.size;
5614 ['xs','sm','md','lg'].map(function(size){
5615 if (settings[size]) {
5616 cfg.cls += ' col-' + size + '-' + settings[size];
5620 var inputblock = input;
5622 if (this.before || this.after) {
5625 cls : 'input-group',
5629 inputblock.cn.push({
5631 cls : 'input-group-addon',
5635 inputblock.cn.push(input);
5637 inputblock.cn.push({
5639 cls : 'input-group-addon',
5646 if (align ==='left' && this.fieldLabel.length) {
5647 Roo.log("left and has label");
5653 cls : 'control-label col-sm-' + this.labelWidth,
5654 html : this.fieldLabel
5658 cls : "col-sm-" + (12 - this.labelWidth),
5665 } else if ( this.fieldLabel.length) {
5671 //cls : 'input-group-addon',
5672 html : this.fieldLabel
5682 Roo.log(" no label && no align");
5691 Roo.log('input-parentType: ' + this.parentType);
5693 if (this.parentType === 'Navbar' && this.parent().bar) {
5694 cfg.cls += ' navbar-form';
5702 * return the real input element.
5704 inputEl: function ()
5706 return this.el.select('input.form-control',true).first();
5708 setDisabled : function(v)
5710 var i = this.inputEl().dom;
5712 i.removeAttribute('disabled');
5716 i.setAttribute('disabled','true');
5718 initEvents : function()
5721 this.inputEl().on("keydown" , this.fireKey, this);
5722 this.inputEl().on("focus", this.onFocus, this);
5723 this.inputEl().on("blur", this.onBlur, this);
5725 this.inputEl().relayEvent('keyup', this);
5727 // reference to original value for reset
5728 this.originalValue = this.getValue();
5729 //Roo.form.TextField.superclass.initEvents.call(this);
5730 if(this.validationEvent == 'keyup'){
5731 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
5732 this.inputEl().on('keyup', this.filterValidation, this);
5734 else if(this.validationEvent !== false){
5735 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
5738 if(this.selectOnFocus){
5739 this.on("focus", this.preFocus, this);
5742 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
5743 this.inputEl().on("keypress", this.filterKeys, this);
5746 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
5747 this.el.on("click", this.autoSize, this);
5750 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
5751 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
5755 filterValidation : function(e){
5756 if(!e.isNavKeyPress()){
5757 this.validationTask.delay(this.validationDelay);
5761 * Validates the field value
5762 * @return {Boolean} True if the value is valid, else false
5764 validate : function(){
5765 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
5766 if(this.disabled || this.validateValue(this.getRawValue())){
5767 this.clearInvalid();
5775 * Validates a value according to the field's validation rules and marks the field as invalid
5776 * if the validation fails
5777 * @param {Mixed} value The value to validate
5778 * @return {Boolean} True if the value is valid, else false
5780 validateValue : function(value){
5781 if(value.length < 1) { // if it's blank
5782 if(this.allowBlank){
5783 this.clearInvalid();
5786 this.markInvalid(this.blankText);
5790 if(value.length < this.minLength){
5791 this.markInvalid(String.format(this.minLengthText, this.minLength));
5794 if(value.length > this.maxLength){
5795 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
5799 var vt = Roo.form.VTypes;
5800 if(!vt[this.vtype](value, this)){
5801 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
5805 if(typeof this.validator == "function"){
5806 var msg = this.validator(value);
5808 this.markInvalid(msg);
5812 if(this.regex && !this.regex.test(value)){
5813 this.markInvalid(this.regexText);
5822 fireKey : function(e){
5823 //Roo.log('field ' + e.getKey());
5824 if(e.isNavKeyPress()){
5825 this.fireEvent("specialkey", this, e);
5828 focus : function (selectText){
5830 this.inputEl().focus();
5831 if(selectText === true){
5832 this.inputEl().dom.select();
5838 onFocus : function(){
5839 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
5840 // this.el.addClass(this.focusClass);
5843 this.hasFocus = true;
5844 this.startValue = this.getValue();
5845 this.fireEvent("focus", this);
5849 beforeBlur : Roo.emptyFn,
5853 onBlur : function(){
5855 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
5856 //this.el.removeClass(this.focusClass);
5858 this.hasFocus = false;
5859 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
5862 var v = this.getValue();
5863 if(String(v) !== String(this.startValue)){
5864 this.fireEvent('change', this, v, this.startValue);
5866 this.fireEvent("blur", this);
5870 * Resets the current field value to the originally loaded value and clears any validation messages
5873 this.setValue(this.originalValue);
5874 this.clearInvalid();
5877 * Returns the name of the field
5878 * @return {Mixed} name The name field
5880 getName: function(){
5884 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
5885 * @return {Mixed} value The field value
5887 getValue : function(){
5888 return this.inputEl().getValue();
5891 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
5892 * @return {Mixed} value The field value
5894 getRawValue : function(){
5895 var v = this.inputEl().getValue();
5901 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
5902 * @param {Mixed} value The value to set
5904 setRawValue : function(v){
5905 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
5908 selectText : function(start, end){
5909 var v = this.getRawValue();
5911 start = start === undefined ? 0 : start;
5912 end = end === undefined ? v.length : end;
5913 var d = this.inputEl().dom;
5914 if(d.setSelectionRange){
5915 d.setSelectionRange(start, end);
5916 }else if(d.createTextRange){
5917 var range = d.createTextRange();
5918 range.moveStart("character", start);
5919 range.moveEnd("character", v.length-end);
5926 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
5927 * @param {Mixed} value The value to set
5929 setValue : function(v){
5932 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
5938 processValue : function(value){
5939 if(this.stripCharsRe){
5940 var newValue = value.replace(this.stripCharsRe, '');
5941 if(newValue !== value){
5942 this.setRawValue(newValue);
5949 preFocus : function(){
5951 if(this.selectOnFocus){
5952 this.inputEl().dom.select();
5955 filterKeys : function(e){
5957 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
5960 var c = e.getCharCode(), cc = String.fromCharCode(c);
5961 if(Roo.isIE && (e.isSpecialKey() || !cc)){
5964 if(!this.maskRe.test(cc)){
5969 * Clear any invalid styles/messages for this field
5971 clearInvalid : function(){
5973 if(!this.el || this.preventMark){ // not rendered
5976 this.el.removeClass(this.invalidClass);
5978 switch(this.msgTarget){
5980 this.el.dom.qtip = '';
5983 this.el.dom.title = '';
5987 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
5992 this.errorIcon.dom.qtip = '';
5993 this.errorIcon.hide();
5994 this.un('resize', this.alignErrorIcon, this);
5998 var t = Roo.getDom(this.msgTarget);
6000 t.style.display = 'none';
6004 this.fireEvent('valid', this);
6007 * Mark this field as invalid
6008 * @param {String} msg The validation message
6010 markInvalid : function(msg){
6011 if(!this.el || this.preventMark){ // not rendered
6014 this.el.addClass(this.invalidClass);
6016 msg = msg || this.invalidText;
6017 switch(this.msgTarget){
6019 this.el.dom.qtip = msg;
6020 this.el.dom.qclass = 'x-form-invalid-tip';
6021 if(Roo.QuickTips){ // fix for floating editors interacting with DND
6022 Roo.QuickTips.enable();
6026 this.el.dom.title = msg;
6030 var elp = this.el.findParent('.x-form-element', 5, true);
6031 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
6032 this.errorEl.setWidth(elp.getWidth(true)-20);
6034 this.errorEl.update(msg);
6035 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
6038 if(!this.errorIcon){
6039 var elp = this.el.findParent('.x-form-element', 5, true);
6040 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
6042 this.alignErrorIcon();
6043 this.errorIcon.dom.qtip = msg;
6044 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
6045 this.errorIcon.show();
6046 this.on('resize', this.alignErrorIcon, this);
6049 var t = Roo.getDom(this.msgTarget);
6051 t.style.display = this.msgDisplay;
6055 this.fireEvent('invalid', this, msg);
6058 SafariOnKeyDown : function(event)
6060 // this is a workaround for a password hang bug on chrome/ webkit.
6062 var isSelectAll = false;
6064 if(this.inputEl().dom.selectionEnd > 0){
6065 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
6067 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
6068 event.preventDefault();
6073 if(isSelectAll){ // backspace and delete key
6075 event.preventDefault();
6076 // this is very hacky as keydown always get's upper case.
6078 var cc = String.fromCharCode(event.getCharCode());
6079 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
6083 adjustWidth : function(tag, w){
6084 tag = tag.toLowerCase();
6085 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
6086 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
6090 if(tag == 'textarea'){
6093 }else if(Roo.isOpera){
6097 if(tag == 'textarea'){
6116 * @class Roo.bootstrap.TextArea
6117 * @extends Roo.bootstrap.Input
6118 * Bootstrap TextArea class
6119 * @cfg {Number} cols Specifies the visible width of a text area
6120 * @cfg {Number} rows Specifies the visible number of lines in a text area
6121 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
6122 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
6123 * @cfg {string} html text
6126 * Create a new TextArea
6127 * @param {Object} config The config object
6130 Roo.bootstrap.TextArea = function(config){
6131 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
6135 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
6145 getAutoCreate : function(){
6147 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6158 value : this.value || '',
6159 html: this.html || '',
6160 cls : 'form-control',
6161 placeholder : this.placeholder || ''
6165 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6166 input.maxLength = this.maxLength;
6170 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
6174 input.cols = this.cols;
6177 if (this.readOnly) {
6178 input.readonly = true;
6182 input.name = this.name;
6186 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
6190 ['xs','sm','md','lg'].map(function(size){
6191 if (settings[size]) {
6192 cfg.cls += ' col-' + size + '-' + settings[size];
6196 var inputblock = input;
6198 if (this.before || this.after) {
6201 cls : 'input-group',
6205 inputblock.cn.push({
6207 cls : 'input-group-addon',
6211 inputblock.cn.push(input);
6213 inputblock.cn.push({
6215 cls : 'input-group-addon',
6222 if (align ==='left' && this.fieldLabel.length) {
6223 Roo.log("left and has label");
6229 cls : 'control-label col-sm-' + this.labelWidth,
6230 html : this.fieldLabel
6234 cls : "col-sm-" + (12 - this.labelWidth),
6241 } else if ( this.fieldLabel.length) {
6247 //cls : 'input-group-addon',
6248 html : this.fieldLabel
6258 Roo.log(" no label && no align");
6268 if (this.disabled) {
6269 input.disabled=true;
6276 * return the real textarea element.
6278 inputEl: function ()
6280 return this.el.select('textarea.form-control',true).first();
6288 * trigger field - base class for combo..
6293 * @class Roo.bootstrap.TriggerField
6294 * @extends Roo.bootstrap.Input
6295 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
6296 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
6297 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
6298 * for which you can provide a custom implementation. For example:
6300 var trigger = new Roo.bootstrap.TriggerField();
6301 trigger.onTriggerClick = myTriggerFn;
6302 trigger.applyTo('my-field');
6305 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
6306 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
6307 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
6308 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
6310 * Create a new TriggerField.
6311 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
6312 * to the base TextField)
6314 Roo.bootstrap.TriggerField = function(config){
6315 this.mimicing = false;
6316 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
6319 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
6321 * @cfg {String} triggerClass A CSS class to apply to the trigger
6324 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
6328 /** @cfg {Boolean} grow @hide */
6329 /** @cfg {Number} growMin @hide */
6330 /** @cfg {Number} growMax @hide */
6336 autoSize: Roo.emptyFn,
6343 actionMode : 'wrap',
6347 getAutoCreate : function(){
6349 var parent = this.parent();
6351 var align = this.parentLabelAlign();
6356 cls: 'form-group' //input-group
6363 type : this.inputType,
6364 cls : 'form-control',
6365 autocomplete: 'off',
6366 placeholder : this.placeholder || ''
6370 input.name = this.name;
6373 input.cls += ' input-' + this.size;
6376 if (this.disabled) {
6377 input.disabled=true;
6380 var inputblock = input;
6382 if (this.before || this.after) {
6385 cls : 'input-group',
6389 inputblock.cn.push({
6391 cls : 'input-group-addon',
6395 inputblock.cn.push(input);
6397 inputblock.cn.push({
6399 cls : 'input-group-addon',
6412 cls: 'form-hidden-field'
6420 Roo.log('multiple');
6428 cls: 'form-hidden-field'
6432 cls: 'select2-choices',
6436 cls: 'select2-search-field',
6449 cls: 'select2-container input-group',
6454 cls: 'typeahead typeahead-long dropdown-menu',
6455 style: 'display:none'
6463 cls : 'input-group-addon btn dropdown-toggle',
6471 cls: 'combobox-clear',
6485 combobox.cls += ' select2-container-multi';
6488 if (align ==='left' && this.fieldLabel.length) {
6490 Roo.log("left and has label");
6496 cls : 'control-label col-sm-' + this.labelWidth,
6497 html : this.fieldLabel
6501 cls : "col-sm-" + (12 - this.labelWidth),
6508 } else if ( this.fieldLabel.length) {
6514 //cls : 'input-group-addon',
6515 html : this.fieldLabel
6525 Roo.log(" no label && no align");
6532 ['xs','sm','md','lg'].map(function(size){
6533 if (settings[size]) {
6534 cfg.cls += ' col-' + size + '-' + settings[size];
6545 onResize : function(w, h){
6546 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
6547 // if(typeof w == 'number'){
6548 // var x = w - this.trigger.getWidth();
6549 // this.inputEl().setWidth(this.adjustWidth('input', x));
6550 // this.trigger.setStyle('left', x+'px');
6555 adjustSize : Roo.BoxComponent.prototype.adjustSize,
6558 getResizeEl : function(){
6559 return this.inputEl();
6563 getPositionEl : function(){
6564 return this.inputEl();
6568 alignErrorIcon : function(){
6569 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
6573 initEvents : function(){
6575 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
6576 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
6578 this.trigger = this.el.select('span.dropdown-toggle',true).first();
6579 if(this.hideTrigger){
6580 this.trigger.setDisplayed(false);
6582 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
6586 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
6589 //this.trigger.addClassOnOver('x-form-trigger-over');
6590 //this.trigger.addClassOnClick('x-form-trigger-click');
6593 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
6598 initTrigger : function(){
6603 onDestroy : function(){
6605 this.trigger.removeAllListeners();
6606 // this.trigger.remove();
6609 // this.wrap.remove();
6611 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
6615 onFocus : function(){
6616 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
6619 this.wrap.addClass('x-trigger-wrap-focus');
6620 this.mimicing = true;
6621 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
6622 if(this.monitorTab){
6623 this.el.on("keydown", this.checkTab, this);
6630 checkTab : function(e){
6631 if(e.getKey() == e.TAB){
6637 onBlur : function(){
6642 mimicBlur : function(e, t){
6644 if(!this.wrap.contains(t) && this.validateBlur()){
6651 triggerBlur : function(){
6652 this.mimicing = false;
6653 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
6654 if(this.monitorTab){
6655 this.el.un("keydown", this.checkTab, this);
6657 //this.wrap.removeClass('x-trigger-wrap-focus');
6658 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
6662 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
6663 validateBlur : function(e, t){
6668 onDisable : function(){
6669 Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
6671 // this.wrap.addClass('x-item-disabled');
6676 onEnable : function(){
6677 Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
6679 // this.el.removeClass('x-item-disabled');
6684 onShow : function(){
6685 var ae = this.getActionEl();
6688 ae.dom.style.display = '';
6689 ae.dom.style.visibility = 'visible';
6695 onHide : function(){
6696 var ae = this.getActionEl();
6697 ae.dom.style.display = 'none';
6701 * The function that should handle the trigger's click event. This method does nothing by default until overridden
6702 * by an implementing function.
6704 * @param {EventObject} e
6706 onTriggerClick : Roo.emptyFn
6710 * Ext JS Library 1.1.1
6711 * Copyright(c) 2006-2007, Ext JS, LLC.
6713 * Originally Released Under LGPL - original licence link has changed is not relivant.
6716 * <script type="text/javascript">
6721 * @class Roo.data.SortTypes
6723 * Defines the default sorting (casting?) comparison functions used when sorting data.
6725 Roo.data.SortTypes = {
6727 * Default sort that does nothing
6728 * @param {Mixed} s The value being converted
6729 * @return {Mixed} The comparison value
6736 * The regular expression used to strip tags
6740 stripTagsRE : /<\/?[^>]+>/gi,
6743 * Strips all HTML tags to sort on text only
6744 * @param {Mixed} s The value being converted
6745 * @return {String} The comparison value
6747 asText : function(s){
6748 return String(s).replace(this.stripTagsRE, "");
6752 * Strips all HTML tags to sort on text only - Case insensitive
6753 * @param {Mixed} s The value being converted
6754 * @return {String} The comparison value
6756 asUCText : function(s){
6757 return String(s).toUpperCase().replace(this.stripTagsRE, "");
6761 * Case insensitive string
6762 * @param {Mixed} s The value being converted
6763 * @return {String} The comparison value
6765 asUCString : function(s) {
6766 return String(s).toUpperCase();
6771 * @param {Mixed} s The value being converted
6772 * @return {Number} The comparison value
6774 asDate : function(s) {
6778 if(s instanceof Date){
6781 return Date.parse(String(s));
6786 * @param {Mixed} s The value being converted
6787 * @return {Float} The comparison value
6789 asFloat : function(s) {
6790 var val = parseFloat(String(s).replace(/,/g, ""));
6791 if(isNaN(val)) val = 0;
6797 * @param {Mixed} s The value being converted
6798 * @return {Number} The comparison value
6800 asInt : function(s) {
6801 var val = parseInt(String(s).replace(/,/g, ""));
6802 if(isNaN(val)) val = 0;
6807 * Ext JS Library 1.1.1
6808 * Copyright(c) 2006-2007, Ext JS, LLC.
6810 * Originally Released Under LGPL - original licence link has changed is not relivant.
6813 * <script type="text/javascript">
6817 * @class Roo.data.Record
6818 * Instances of this class encapsulate both record <em>definition</em> information, and record
6819 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
6820 * to access Records cached in an {@link Roo.data.Store} object.<br>
6822 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
6823 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
6826 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
6828 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
6829 * {@link #create}. The parameters are the same.
6830 * @param {Array} data An associative Array of data values keyed by the field name.
6831 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
6832 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
6833 * not specified an integer id is generated.
6835 Roo.data.Record = function(data, id){
6836 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
6841 * Generate a constructor for a specific record layout.
6842 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
6843 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
6844 * Each field definition object may contain the following properties: <ul>
6845 * <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,
6846 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
6847 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
6848 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
6849 * is being used, then this is a string containing the javascript expression to reference the data relative to
6850 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
6851 * to the data item relative to the record element. If the mapping expression is the same as the field name,
6852 * this may be omitted.</p></li>
6853 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
6854 * <ul><li>auto (Default, implies no conversion)</li>
6859 * <li>date</li></ul></p></li>
6860 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
6861 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
6862 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
6863 * by the Reader into an object that will be stored in the Record. It is passed the
6864 * following parameters:<ul>
6865 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
6867 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
6869 * <br>usage:<br><pre><code>
6870 var TopicRecord = Roo.data.Record.create(
6871 {name: 'title', mapping: 'topic_title'},
6872 {name: 'author', mapping: 'username'},
6873 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
6874 {name: 'lastPost', mapping: 'post_time', type: 'date'},
6875 {name: 'lastPoster', mapping: 'user2'},
6876 {name: 'excerpt', mapping: 'post_text'}
6879 var myNewRecord = new TopicRecord({
6880 title: 'Do my job please',
6883 lastPost: new Date(),
6884 lastPoster: 'Animal',
6885 excerpt: 'No way dude!'
6887 myStore.add(myNewRecord);
6892 Roo.data.Record.create = function(o){
6894 f.superclass.constructor.apply(this, arguments);
6896 Roo.extend(f, Roo.data.Record);
6897 var p = f.prototype;
6898 p.fields = new Roo.util.MixedCollection(false, function(field){
6901 for(var i = 0, len = o.length; i < len; i++){
6902 p.fields.add(new Roo.data.Field(o[i]));
6904 f.getField = function(name){
6905 return p.fields.get(name);
6910 Roo.data.Record.AUTO_ID = 1000;
6911 Roo.data.Record.EDIT = 'edit';
6912 Roo.data.Record.REJECT = 'reject';
6913 Roo.data.Record.COMMIT = 'commit';
6915 Roo.data.Record.prototype = {
6917 * Readonly flag - true if this record has been modified.
6926 join : function(store){
6931 * Set the named field to the specified value.
6932 * @param {String} name The name of the field to set.
6933 * @param {Object} value The value to set the field to.
6935 set : function(name, value){
6936 if(this.data[name] == value){
6943 if(typeof this.modified[name] == 'undefined'){
6944 this.modified[name] = this.data[name];
6946 this.data[name] = value;
6947 if(!this.editing && this.store){
6948 this.store.afterEdit(this);
6953 * Get the value of the named field.
6954 * @param {String} name The name of the field to get the value of.
6955 * @return {Object} The value of the field.
6957 get : function(name){
6958 return this.data[name];
6962 beginEdit : function(){
6963 this.editing = true;
6968 cancelEdit : function(){
6969 this.editing = false;
6970 delete this.modified;
6974 endEdit : function(){
6975 this.editing = false;
6976 if(this.dirty && this.store){
6977 this.store.afterEdit(this);
6982 * Usually called by the {@link Roo.data.Store} which owns the Record.
6983 * Rejects all changes made to the Record since either creation, or the last commit operation.
6984 * Modified fields are reverted to their original values.
6986 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
6987 * of reject operations.
6989 reject : function(){
6990 var m = this.modified;
6992 if(typeof m[n] != "function"){
6993 this.data[n] = m[n];
6997 delete this.modified;
6998 this.editing = false;
7000 this.store.afterReject(this);
7005 * Usually called by the {@link Roo.data.Store} which owns the Record.
7006 * Commits all changes made to the Record since either creation, or the last commit operation.
7008 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
7009 * of commit operations.
7011 commit : function(){
7013 delete this.modified;
7014 this.editing = false;
7016 this.store.afterCommit(this);
7021 hasError : function(){
7022 return this.error != null;
7026 clearError : function(){
7031 * Creates a copy of this record.
7032 * @param {String} id (optional) A new record id if you don't want to use this record's id
7035 copy : function(newId) {
7036 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
7040 * Ext JS Library 1.1.1
7041 * Copyright(c) 2006-2007, Ext JS, LLC.
7043 * Originally Released Under LGPL - original licence link has changed is not relivant.
7046 * <script type="text/javascript">
7052 * @class Roo.data.Store
7053 * @extends Roo.util.Observable
7054 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
7055 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
7057 * 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
7058 * has no knowledge of the format of the data returned by the Proxy.<br>
7060 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
7061 * instances from the data object. These records are cached and made available through accessor functions.
7063 * Creates a new Store.
7064 * @param {Object} config A config object containing the objects needed for the Store to access data,
7065 * and read the data into Records.
7067 Roo.data.Store = function(config){
7068 this.data = new Roo.util.MixedCollection(false);
7069 this.data.getKey = function(o){
7072 this.baseParams = {};
7079 "multisort" : "_multisort"
7082 if(config && config.data){
7083 this.inlineData = config.data;
7087 Roo.apply(this, config);
7089 if(this.reader){ // reader passed
7090 this.reader = Roo.factory(this.reader, Roo.data);
7091 this.reader.xmodule = this.xmodule || false;
7092 if(!this.recordType){
7093 this.recordType = this.reader.recordType;
7095 if(this.reader.onMetaChange){
7096 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
7100 if(this.recordType){
7101 this.fields = this.recordType.prototype.fields;
7107 * @event datachanged
7108 * Fires when the data cache has changed, and a widget which is using this Store
7109 * as a Record cache should refresh its view.
7110 * @param {Store} this
7115 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
7116 * @param {Store} this
7117 * @param {Object} meta The JSON metadata
7122 * Fires when Records have been added to the Store
7123 * @param {Store} this
7124 * @param {Roo.data.Record[]} records The array of Records added
7125 * @param {Number} index The index at which the record(s) were added
7130 * Fires when a Record has been removed from the Store
7131 * @param {Store} this
7132 * @param {Roo.data.Record} record The Record that was removed
7133 * @param {Number} index The index at which the record was removed
7138 * Fires when a Record has been updated
7139 * @param {Store} this
7140 * @param {Roo.data.Record} record The Record that was updated
7141 * @param {String} operation The update operation being performed. Value may be one of:
7143 Roo.data.Record.EDIT
7144 Roo.data.Record.REJECT
7145 Roo.data.Record.COMMIT
7151 * Fires when the data cache has been cleared.
7152 * @param {Store} this
7157 * Fires before a request is made for a new data object. If the beforeload handler returns false
7158 * the load action will be canceled.
7159 * @param {Store} this
7160 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7164 * @event beforeloadadd
7165 * Fires after a new set of Records has been loaded.
7166 * @param {Store} this
7167 * @param {Roo.data.Record[]} records The Records that were loaded
7168 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7170 beforeloadadd : true,
7173 * Fires after a new set of Records has been loaded, before they are added to the store.
7174 * @param {Store} this
7175 * @param {Roo.data.Record[]} records The Records that were loaded
7176 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7177 * @params {Object} return from reader
7181 * @event loadexception
7182 * Fires if an exception occurs in the Proxy during loading.
7183 * Called with the signature of the Proxy's "loadexception" event.
7184 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
7187 * @param {Object} return from JsonData.reader() - success, totalRecords, records
7188 * @param {Object} load options
7189 * @param {Object} jsonData from your request (normally this contains the Exception)
7191 loadexception : true
7195 this.proxy = Roo.factory(this.proxy, Roo.data);
7196 this.proxy.xmodule = this.xmodule || false;
7197 this.relayEvents(this.proxy, ["loadexception"]);
7199 this.sortToggle = {};
7200 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
7202 Roo.data.Store.superclass.constructor.call(this);
7204 if(this.inlineData){
7205 this.loadData(this.inlineData);
7206 delete this.inlineData;
7210 Roo.extend(Roo.data.Store, Roo.util.Observable, {
7212 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
7213 * without a remote query - used by combo/forms at present.
7217 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
7220 * @cfg {Array} data Inline data to be loaded when the store is initialized.
7223 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
7224 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
7227 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
7228 * on any HTTP request
7231 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
7234 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
7238 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
7239 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
7244 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
7245 * loaded or when a record is removed. (defaults to false).
7247 pruneModifiedRecords : false,
7253 * Add Records to the Store and fires the add event.
7254 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
7256 add : function(records){
7257 records = [].concat(records);
7258 for(var i = 0, len = records.length; i < len; i++){
7259 records[i].join(this);
7261 var index = this.data.length;
7262 this.data.addAll(records);
7263 this.fireEvent("add", this, records, index);
7267 * Remove a Record from the Store and fires the remove event.
7268 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
7270 remove : function(record){
7271 var index = this.data.indexOf(record);
7272 this.data.removeAt(index);
7273 if(this.pruneModifiedRecords){
7274 this.modified.remove(record);
7276 this.fireEvent("remove", this, record, index);
7280 * Remove all Records from the Store and fires the clear event.
7282 removeAll : function(){
7284 if(this.pruneModifiedRecords){
7287 this.fireEvent("clear", this);
7291 * Inserts Records to the Store at the given index and fires the add event.
7292 * @param {Number} index The start index at which to insert the passed Records.
7293 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
7295 insert : function(index, records){
7296 records = [].concat(records);
7297 for(var i = 0, len = records.length; i < len; i++){
7298 this.data.insert(index, records[i]);
7299 records[i].join(this);
7301 this.fireEvent("add", this, records, index);
7305 * Get the index within the cache of the passed Record.
7306 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
7307 * @return {Number} The index of the passed Record. Returns -1 if not found.
7309 indexOf : function(record){
7310 return this.data.indexOf(record);
7314 * Get the index within the cache of the Record with the passed id.
7315 * @param {String} id The id of the Record to find.
7316 * @return {Number} The index of the Record. Returns -1 if not found.
7318 indexOfId : function(id){
7319 return this.data.indexOfKey(id);
7323 * Get the Record with the specified id.
7324 * @param {String} id The id of the Record to find.
7325 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
7327 getById : function(id){
7328 return this.data.key(id);
7332 * Get the Record at the specified index.
7333 * @param {Number} index The index of the Record to find.
7334 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
7336 getAt : function(index){
7337 return this.data.itemAt(index);
7341 * Returns a range of Records between specified indices.
7342 * @param {Number} startIndex (optional) The starting index (defaults to 0)
7343 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
7344 * @return {Roo.data.Record[]} An array of Records
7346 getRange : function(start, end){
7347 return this.data.getRange(start, end);
7351 storeOptions : function(o){
7352 o = Roo.apply({}, o);
7355 this.lastOptions = o;
7359 * Loads the Record cache from the configured Proxy using the configured Reader.
7361 * If using remote paging, then the first load call must specify the <em>start</em>
7362 * and <em>limit</em> properties in the options.params property to establish the initial
7363 * position within the dataset, and the number of Records to cache on each read from the Proxy.
7365 * <strong>It is important to note that for remote data sources, loading is asynchronous,
7366 * and this call will return before the new data has been loaded. Perform any post-processing
7367 * in a callback function, or in a "load" event handler.</strong>
7369 * @param {Object} options An object containing properties which control loading options:<ul>
7370 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
7371 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
7372 * passed the following arguments:<ul>
7373 * <li>r : Roo.data.Record[]</li>
7374 * <li>options: Options object from the load call</li>
7375 * <li>success: Boolean success indicator</li></ul></li>
7376 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
7377 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
7380 load : function(options){
7381 options = options || {};
7382 if(this.fireEvent("beforeload", this, options) !== false){
7383 this.storeOptions(options);
7384 var p = Roo.apply(options.params || {}, this.baseParams);
7385 // if meta was not loaded from remote source.. try requesting it.
7386 if (!this.reader.metaFromRemote) {
7389 if(this.sortInfo && this.remoteSort){
7390 var pn = this.paramNames;
7391 p[pn["sort"]] = this.sortInfo.field;
7392 p[pn["dir"]] = this.sortInfo.direction;
7394 if (this.multiSort) {
7395 var pn = this.paramNames;
7396 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
7399 this.proxy.load(p, this.reader, this.loadRecords, this, options);
7404 * Reloads the Record cache from the configured Proxy using the configured Reader and
7405 * the options from the last load operation performed.
7406 * @param {Object} options (optional) An object containing properties which may override the options
7407 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
7408 * the most recently used options are reused).
7410 reload : function(options){
7411 this.load(Roo.applyIf(options||{}, this.lastOptions));
7415 // Called as a callback by the Reader during a load operation.
7416 loadRecords : function(o, options, success){
7417 if(!o || success === false){
7418 if(success !== false){
7419 this.fireEvent("load", this, [], options, o);
7421 if(options.callback){
7422 options.callback.call(options.scope || this, [], options, false);
7426 // if data returned failure - throw an exception.
7427 if (o.success === false) {
7428 // show a message if no listener is registered.
7429 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
7430 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
7432 // loadmask wil be hooked into this..
7433 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
7436 var r = o.records, t = o.totalRecords || r.length;
7438 this.fireEvent("beforeloadadd", this, r, options, o);
7440 if(!options || options.add !== true){
7441 if(this.pruneModifiedRecords){
7444 for(var i = 0, len = r.length; i < len; i++){
7448 this.data = this.snapshot;
7449 delete this.snapshot;
7452 this.data.addAll(r);
7453 this.totalLength = t;
7455 this.fireEvent("datachanged", this);
7457 this.totalLength = Math.max(t, this.data.length+r.length);
7460 this.fireEvent("load", this, r, options, o);
7461 if(options.callback){
7462 options.callback.call(options.scope || this, r, options, true);
7468 * Loads data from a passed data block. A Reader which understands the format of the data
7469 * must have been configured in the constructor.
7470 * @param {Object} data The data block from which to read the Records. The format of the data expected
7471 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
7472 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
7474 loadData : function(o, append){
7475 var r = this.reader.readRecords(o);
7476 this.loadRecords(r, {add: append}, true);
7480 * Gets the number of cached records.
7482 * <em>If using paging, this may not be the total size of the dataset. If the data object
7483 * used by the Reader contains the dataset size, then the getTotalCount() function returns
7484 * the data set size</em>
7486 getCount : function(){
7487 return this.data.length || 0;
7491 * Gets the total number of records in the dataset as returned by the server.
7493 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
7494 * the dataset size</em>
7496 getTotalCount : function(){
7497 return this.totalLength || 0;
7501 * Returns the sort state of the Store as an object with two properties:
7503 field {String} The name of the field by which the Records are sorted
7504 direction {String} The sort order, "ASC" or "DESC"
7507 getSortState : function(){
7508 return this.sortInfo;
7512 applySort : function(){
7513 if(this.sortInfo && !this.remoteSort){
7514 var s = this.sortInfo, f = s.field;
7515 var st = this.fields.get(f).sortType;
7516 var fn = function(r1, r2){
7517 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
7518 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
7520 this.data.sort(s.direction, fn);
7521 if(this.snapshot && this.snapshot != this.data){
7522 this.snapshot.sort(s.direction, fn);
7528 * Sets the default sort column and order to be used by the next load operation.
7529 * @param {String} fieldName The name of the field to sort by.
7530 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
7532 setDefaultSort : function(field, dir){
7533 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
7538 * If remote sorting is used, the sort is performed on the server, and the cache is
7539 * reloaded. If local sorting is used, the cache is sorted internally.
7540 * @param {String} fieldName The name of the field to sort by.
7541 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
7543 sort : function(fieldName, dir){
7544 var f = this.fields.get(fieldName);
7546 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
7548 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
7549 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
7554 this.sortToggle[f.name] = dir;
7555 this.sortInfo = {field: f.name, direction: dir};
7556 if(!this.remoteSort){
7558 this.fireEvent("datachanged", this);
7560 this.load(this.lastOptions);
7565 * Calls the specified function for each of the Records in the cache.
7566 * @param {Function} fn The function to call. The Record is passed as the first parameter.
7567 * Returning <em>false</em> aborts and exits the iteration.
7568 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
7570 each : function(fn, scope){
7571 this.data.each(fn, scope);
7575 * Gets all records modified since the last commit. Modified records are persisted across load operations
7576 * (e.g., during paging).
7577 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
7579 getModifiedRecords : function(){
7580 return this.modified;
7584 createFilterFn : function(property, value, anyMatch){
7585 if(!value.exec){ // not a regex
7586 value = String(value);
7587 if(value.length == 0){
7590 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
7593 return value.test(r.data[property]);
7598 * Sums the value of <i>property</i> for each record between start and end and returns the result.
7599 * @param {String} property A field on your records
7600 * @param {Number} start The record index to start at (defaults to 0)
7601 * @param {Number} end The last record index to include (defaults to length - 1)
7602 * @return {Number} The sum
7604 sum : function(property, start, end){
7605 var rs = this.data.items, v = 0;
7607 end = (end || end === 0) ? end : rs.length-1;
7609 for(var i = start; i <= end; i++){
7610 v += (rs[i].data[property] || 0);
7616 * Filter the records by a specified property.
7617 * @param {String} field A field on your records
7618 * @param {String/RegExp} value Either a string that the field
7619 * should start with or a RegExp to test against the field
7620 * @param {Boolean} anyMatch True to match any part not just the beginning
7622 filter : function(property, value, anyMatch){
7623 var fn = this.createFilterFn(property, value, anyMatch);
7624 return fn ? this.filterBy(fn) : this.clearFilter();
7628 * Filter by a function. The specified function will be called with each
7629 * record in this data source. If the function returns true the record is included,
7630 * otherwise it is filtered.
7631 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
7632 * @param {Object} scope (optional) The scope of the function (defaults to this)
7634 filterBy : function(fn, scope){
7635 this.snapshot = this.snapshot || this.data;
7636 this.data = this.queryBy(fn, scope||this);
7637 this.fireEvent("datachanged", this);
7641 * Query the records by a specified property.
7642 * @param {String} field A field on your records
7643 * @param {String/RegExp} value Either a string that the field
7644 * should start with or a RegExp to test against the field
7645 * @param {Boolean} anyMatch True to match any part not just the beginning
7646 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
7648 query : function(property, value, anyMatch){
7649 var fn = this.createFilterFn(property, value, anyMatch);
7650 return fn ? this.queryBy(fn) : this.data.clone();
7654 * Query by a function. The specified function will be called with each
7655 * record in this data source. If the function returns true the record is included
7657 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
7658 * @param {Object} scope (optional) The scope of the function (defaults to this)
7659 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
7661 queryBy : function(fn, scope){
7662 var data = this.snapshot || this.data;
7663 return data.filterBy(fn, scope||this);
7667 * Collects unique values for a particular dataIndex from this store.
7668 * @param {String} dataIndex The property to collect
7669 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
7670 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
7671 * @return {Array} An array of the unique values
7673 collect : function(dataIndex, allowNull, bypassFilter){
7674 var d = (bypassFilter === true && this.snapshot) ?
7675 this.snapshot.items : this.data.items;
7676 var v, sv, r = [], l = {};
7677 for(var i = 0, len = d.length; i < len; i++){
7678 v = d[i].data[dataIndex];
7680 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
7689 * Revert to a view of the Record cache with no filtering applied.
7690 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
7692 clearFilter : function(suppressEvent){
7693 if(this.snapshot && this.snapshot != this.data){
7694 this.data = this.snapshot;
7695 delete this.snapshot;
7696 if(suppressEvent !== true){
7697 this.fireEvent("datachanged", this);
7703 afterEdit : function(record){
7704 if(this.modified.indexOf(record) == -1){
7705 this.modified.push(record);
7707 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
7711 afterReject : function(record){
7712 this.modified.remove(record);
7713 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
7717 afterCommit : function(record){
7718 this.modified.remove(record);
7719 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
7723 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
7724 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
7726 commitChanges : function(){
7727 var m = this.modified.slice(0);
7729 for(var i = 0, len = m.length; i < len; i++){
7735 * Cancel outstanding changes on all changed records.
7737 rejectChanges : function(){
7738 var m = this.modified.slice(0);
7740 for(var i = 0, len = m.length; i < len; i++){
7745 onMetaChange : function(meta, rtype, o){
7746 this.recordType = rtype;
7747 this.fields = rtype.prototype.fields;
7748 delete this.snapshot;
7749 this.sortInfo = meta.sortInfo || this.sortInfo;
7751 this.fireEvent('metachange', this, this.reader.meta);
7754 moveIndex : function(data, type)
7756 var index = this.indexOf(data);
7758 var newIndex = index + type;
7762 this.insert(newIndex, data);
7767 * Ext JS Library 1.1.1
7768 * Copyright(c) 2006-2007, Ext JS, LLC.
7770 * Originally Released Under LGPL - original licence link has changed is not relivant.
7773 * <script type="text/javascript">
7777 * @class Roo.data.SimpleStore
7778 * @extends Roo.data.Store
7779 * Small helper class to make creating Stores from Array data easier.
7780 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
7781 * @cfg {Array} fields An array of field definition objects, or field name strings.
7782 * @cfg {Array} data The multi-dimensional array of data
7784 * @param {Object} config
7786 Roo.data.SimpleStore = function(config){
7787 Roo.data.SimpleStore.superclass.constructor.call(this, {
7789 reader: new Roo.data.ArrayReader({
7792 Roo.data.Record.create(config.fields)
7794 proxy : new Roo.data.MemoryProxy(config.data)
7798 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
7800 * Ext JS Library 1.1.1
7801 * Copyright(c) 2006-2007, Ext JS, LLC.
7803 * Originally Released Under LGPL - original licence link has changed is not relivant.
7806 * <script type="text/javascript">
7811 * @extends Roo.data.Store
7812 * @class Roo.data.JsonStore
7813 * Small helper class to make creating Stores for JSON data easier. <br/>
7815 var store = new Roo.data.JsonStore({
7816 url: 'get-images.php',
7818 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
7821 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
7822 * JsonReader and HttpProxy (unless inline data is provided).</b>
7823 * @cfg {Array} fields An array of field definition objects, or field name strings.
7825 * @param {Object} config
7827 Roo.data.JsonStore = function(c){
7828 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
7829 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
7830 reader: new Roo.data.JsonReader(c, c.fields)
7833 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
7835 * Ext JS Library 1.1.1
7836 * Copyright(c) 2006-2007, Ext JS, LLC.
7838 * Originally Released Under LGPL - original licence link has changed is not relivant.
7841 * <script type="text/javascript">
7845 Roo.data.Field = function(config){
7846 if(typeof config == "string"){
7847 config = {name: config};
7849 Roo.apply(this, config);
7855 var st = Roo.data.SortTypes;
7856 // named sortTypes are supported, here we look them up
7857 if(typeof this.sortType == "string"){
7858 this.sortType = st[this.sortType];
7861 // set default sortType for strings and dates
7865 this.sortType = st.asUCString;
7868 this.sortType = st.asDate;
7871 this.sortType = st.none;
7876 var stripRe = /[\$,%]/g;
7878 // prebuilt conversion function for this field, instead of
7879 // switching every time we're reading a value
7881 var cv, dateFormat = this.dateFormat;
7886 cv = function(v){ return v; };
7889 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
7893 return v !== undefined && v !== null && v !== '' ?
7894 parseInt(String(v).replace(stripRe, ""), 10) : '';
7899 return v !== undefined && v !== null && v !== '' ?
7900 parseFloat(String(v).replace(stripRe, ""), 10) : '';
7905 cv = function(v){ return v === true || v === "true" || v == 1; };
7912 if(v instanceof Date){
7916 if(dateFormat == "timestamp"){
7917 return new Date(v*1000);
7919 return Date.parseDate(v, dateFormat);
7921 var parsed = Date.parse(v);
7922 return parsed ? new Date(parsed) : null;
7931 Roo.data.Field.prototype = {
7939 * Ext JS Library 1.1.1
7940 * Copyright(c) 2006-2007, Ext JS, LLC.
7942 * Originally Released Under LGPL - original licence link has changed is not relivant.
7945 * <script type="text/javascript">
7948 // Base class for reading structured data from a data source. This class is intended to be
7949 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
7952 * @class Roo.data.DataReader
7953 * Base class for reading structured data from a data source. This class is intended to be
7954 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
7957 Roo.data.DataReader = function(meta, recordType){
7961 this.recordType = recordType instanceof Array ?
7962 Roo.data.Record.create(recordType) : recordType;
7965 Roo.data.DataReader.prototype = {
7967 * Create an empty record
7968 * @param {Object} data (optional) - overlay some values
7969 * @return {Roo.data.Record} record created.
7971 newRow : function(d) {
7973 this.recordType.prototype.fields.each(function(c) {
7975 case 'int' : da[c.name] = 0; break;
7976 case 'date' : da[c.name] = new Date(); break;
7977 case 'float' : da[c.name] = 0.0; break;
7978 case 'boolean' : da[c.name] = false; break;
7979 default : da[c.name] = ""; break;
7983 return new this.recordType(Roo.apply(da, d));
7988 * Ext JS Library 1.1.1
7989 * Copyright(c) 2006-2007, Ext JS, LLC.
7991 * Originally Released Under LGPL - original licence link has changed is not relivant.
7994 * <script type="text/javascript">
7998 * @class Roo.data.DataProxy
7999 * @extends Roo.data.Observable
8000 * This class is an abstract base class for implementations which provide retrieval of
8001 * unformatted data objects.<br>
8003 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
8004 * (of the appropriate type which knows how to parse the data object) to provide a block of
8005 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
8007 * Custom implementations must implement the load method as described in
8008 * {@link Roo.data.HttpProxy#load}.
8010 Roo.data.DataProxy = function(){
8014 * Fires before a network request is made to retrieve a data object.
8015 * @param {Object} This DataProxy object.
8016 * @param {Object} params The params parameter to the load function.
8021 * Fires before the load method's callback is called.
8022 * @param {Object} This DataProxy object.
8023 * @param {Object} o The data object.
8024 * @param {Object} arg The callback argument object passed to the load function.
8028 * @event loadexception
8029 * Fires if an Exception occurs during data retrieval.
8030 * @param {Object} This DataProxy object.
8031 * @param {Object} o The data object.
8032 * @param {Object} arg The callback argument object passed to the load function.
8033 * @param {Object} e The Exception.
8035 loadexception : true
8037 Roo.data.DataProxy.superclass.constructor.call(this);
8040 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
8043 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
8047 * Ext JS Library 1.1.1
8048 * Copyright(c) 2006-2007, Ext JS, LLC.
8050 * Originally Released Under LGPL - original licence link has changed is not relivant.
8053 * <script type="text/javascript">
8056 * @class Roo.data.MemoryProxy
8057 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
8058 * to the Reader when its load method is called.
8060 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
8062 Roo.data.MemoryProxy = function(data){
8066 Roo.data.MemoryProxy.superclass.constructor.call(this);
8070 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
8072 * Load data from the requested source (in this case an in-memory
8073 * data object passed to the constructor), read the data object into
8074 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
8075 * process that block using the passed callback.
8076 * @param {Object} params This parameter is not used by the MemoryProxy class.
8077 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8078 * object into a block of Roo.data.Records.
8079 * @param {Function} callback The function into which to pass the block of Roo.data.records.
8080 * The function must be passed <ul>
8081 * <li>The Record block object</li>
8082 * <li>The "arg" argument from the load function</li>
8083 * <li>A boolean success indicator</li>
8085 * @param {Object} scope The scope in which to call the callback
8086 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8088 load : function(params, reader, callback, scope, arg){
8089 params = params || {};
8092 result = reader.readRecords(this.data);
8094 this.fireEvent("loadexception", this, arg, null, e);
8095 callback.call(scope, null, arg, false);
8098 callback.call(scope, result, arg, true);
8102 update : function(params, records){
8107 * Ext JS Library 1.1.1
8108 * Copyright(c) 2006-2007, Ext JS, LLC.
8110 * Originally Released Under LGPL - original licence link has changed is not relivant.
8113 * <script type="text/javascript">
8116 * @class Roo.data.HttpProxy
8117 * @extends Roo.data.DataProxy
8118 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
8119 * configured to reference a certain URL.<br><br>
8121 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
8122 * from which the running page was served.<br><br>
8124 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
8126 * Be aware that to enable the browser to parse an XML document, the server must set
8127 * the Content-Type header in the HTTP response to "text/xml".
8129 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
8130 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
8131 * will be used to make the request.
8133 Roo.data.HttpProxy = function(conn){
8134 Roo.data.HttpProxy.superclass.constructor.call(this);
8135 // is conn a conn config or a real conn?
8137 this.useAjax = !conn || !conn.events;
8141 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
8142 // thse are take from connection...
8145 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
8148 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
8149 * extra parameters to each request made by this object. (defaults to undefined)
8152 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
8153 * to each request made by this object. (defaults to undefined)
8156 * @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)
8159 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
8162 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
8168 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
8172 * Return the {@link Roo.data.Connection} object being used by this Proxy.
8173 * @return {Connection} The Connection object. This object may be used to subscribe to events on
8174 * a finer-grained basis than the DataProxy events.
8176 getConnection : function(){
8177 return this.useAjax ? Roo.Ajax : this.conn;
8181 * Load data from the configured {@link Roo.data.Connection}, read the data object into
8182 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
8183 * process that block using the passed callback.
8184 * @param {Object} params An object containing properties which are to be used as HTTP parameters
8185 * for the request to the remote server.
8186 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8187 * object into a block of Roo.data.Records.
8188 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
8189 * The function must be passed <ul>
8190 * <li>The Record block object</li>
8191 * <li>The "arg" argument from the load function</li>
8192 * <li>A boolean success indicator</li>
8194 * @param {Object} scope The scope in which to call the callback
8195 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8197 load : function(params, reader, callback, scope, arg){
8198 if(this.fireEvent("beforeload", this, params) !== false){
8200 params : params || {},
8202 callback : callback,
8207 callback : this.loadResponse,
8211 Roo.applyIf(o, this.conn);
8212 if(this.activeRequest){
8213 Roo.Ajax.abort(this.activeRequest);
8215 this.activeRequest = Roo.Ajax.request(o);
8217 this.conn.request(o);
8220 callback.call(scope||this, null, arg, false);
8225 loadResponse : function(o, success, response){
8226 delete this.activeRequest;
8228 this.fireEvent("loadexception", this, o, response);
8229 o.request.callback.call(o.request.scope, null, o.request.arg, false);
8234 result = o.reader.read(response);
8236 this.fireEvent("loadexception", this, o, response, e);
8237 o.request.callback.call(o.request.scope, null, o.request.arg, false);
8241 this.fireEvent("load", this, o, o.request.arg);
8242 o.request.callback.call(o.request.scope, result, o.request.arg, true);
8246 update : function(dataSet){
8251 updateResponse : function(dataSet){
8256 * Ext JS Library 1.1.1
8257 * Copyright(c) 2006-2007, Ext JS, LLC.
8259 * Originally Released Under LGPL - original licence link has changed is not relivant.
8262 * <script type="text/javascript">
8266 * @class Roo.data.ScriptTagProxy
8267 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
8268 * other than the originating domain of the running page.<br><br>
8270 * <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
8271 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
8273 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
8274 * source code that is used as the source inside a <script> tag.<br><br>
8276 * In order for the browser to process the returned data, the server must wrap the data object
8277 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
8278 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
8279 * depending on whether the callback name was passed:
8282 boolean scriptTag = false;
8283 String cb = request.getParameter("callback");
8286 response.setContentType("text/javascript");
8288 response.setContentType("application/x-json");
8290 Writer out = response.getWriter();
8292 out.write(cb + "(");
8294 out.print(dataBlock.toJsonString());
8301 * @param {Object} config A configuration object.
8303 Roo.data.ScriptTagProxy = function(config){
8304 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
8305 Roo.apply(this, config);
8306 this.head = document.getElementsByTagName("head")[0];
8309 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
8311 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
8313 * @cfg {String} url The URL from which to request the data object.
8316 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
8320 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
8321 * the server the name of the callback function set up by the load call to process the returned data object.
8322 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
8323 * javascript output which calls this named function passing the data object as its only parameter.
8325 callbackParam : "callback",
8327 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
8328 * name to the request.
8333 * Load data from the configured URL, read the data object into
8334 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
8335 * process that block using the passed callback.
8336 * @param {Object} params An object containing properties which are to be used as HTTP parameters
8337 * for the request to the remote server.
8338 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8339 * object into a block of Roo.data.Records.
8340 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
8341 * The function must be passed <ul>
8342 * <li>The Record block object</li>
8343 * <li>The "arg" argument from the load function</li>
8344 * <li>A boolean success indicator</li>
8346 * @param {Object} scope The scope in which to call the callback
8347 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8349 load : function(params, reader, callback, scope, arg){
8350 if(this.fireEvent("beforeload", this, params) !== false){
8352 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
8355 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
8357 url += "&_dc=" + (new Date().getTime());
8359 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
8362 cb : "stcCallback"+transId,
8363 scriptId : "stcScript"+transId,
8367 callback : callback,
8373 window[trans.cb] = function(o){
8374 conn.handleResponse(o, trans);
8377 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
8379 if(this.autoAbort !== false){
8383 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
8385 var script = document.createElement("script");
8386 script.setAttribute("src", url);
8387 script.setAttribute("type", "text/javascript");
8388 script.setAttribute("id", trans.scriptId);
8389 this.head.appendChild(script);
8393 callback.call(scope||this, null, arg, false);
8398 isLoading : function(){
8399 return this.trans ? true : false;
8403 * Abort the current server request.
8406 if(this.isLoading()){
8407 this.destroyTrans(this.trans);
8412 destroyTrans : function(trans, isLoaded){
8413 this.head.removeChild(document.getElementById(trans.scriptId));
8414 clearTimeout(trans.timeoutId);
8416 window[trans.cb] = undefined;
8418 delete window[trans.cb];
8421 // if hasn't been loaded, wait for load to remove it to prevent script error
8422 window[trans.cb] = function(){
8423 window[trans.cb] = undefined;
8425 delete window[trans.cb];
8432 handleResponse : function(o, trans){
8434 this.destroyTrans(trans, true);
8437 result = trans.reader.readRecords(o);
8439 this.fireEvent("loadexception", this, o, trans.arg, e);
8440 trans.callback.call(trans.scope||window, null, trans.arg, false);
8443 this.fireEvent("load", this, o, trans.arg);
8444 trans.callback.call(trans.scope||window, result, trans.arg, true);
8448 handleFailure : function(trans){
8450 this.destroyTrans(trans, false);
8451 this.fireEvent("loadexception", this, null, trans.arg);
8452 trans.callback.call(trans.scope||window, null, trans.arg, false);
8456 * Ext JS Library 1.1.1
8457 * Copyright(c) 2006-2007, Ext JS, LLC.
8459 * Originally Released Under LGPL - original licence link has changed is not relivant.
8462 * <script type="text/javascript">
8466 * @class Roo.data.JsonReader
8467 * @extends Roo.data.DataReader
8468 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
8469 * based on mappings in a provided Roo.data.Record constructor.
8471 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
8472 * in the reply previously.
8477 var RecordDef = Roo.data.Record.create([
8478 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
8479 {name: 'occupation'} // This field will use "occupation" as the mapping.
8481 var myReader = new Roo.data.JsonReader({
8482 totalProperty: "results", // The property which contains the total dataset size (optional)
8483 root: "rows", // The property which contains an Array of row objects
8484 id: "id" // The property within each row object that provides an ID for the record (optional)
8488 * This would consume a JSON file like this:
8490 { 'results': 2, 'rows': [
8491 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
8492 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
8495 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
8496 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
8497 * paged from the remote server.
8498 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
8499 * @cfg {String} root name of the property which contains the Array of row objects.
8500 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
8502 * Create a new JsonReader
8503 * @param {Object} meta Metadata configuration options
8504 * @param {Object} recordType Either an Array of field definition objects,
8505 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
8507 Roo.data.JsonReader = function(meta, recordType){
8510 // set some defaults:
8512 totalProperty: 'total',
8513 successProperty : 'success',
8518 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
8520 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
8523 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
8524 * Used by Store query builder to append _requestMeta to params.
8527 metaFromRemote : false,
8529 * This method is only used by a DataProxy which has retrieved data from a remote server.
8530 * @param {Object} response The XHR object which contains the JSON data in its responseText.
8531 * @return {Object} data A data block which is used by an Roo.data.Store object as
8532 * a cache of Roo.data.Records.
8534 read : function(response){
8535 var json = response.responseText;
8537 var o = /* eval:var:o */ eval("("+json+")");
8539 throw {message: "JsonReader.read: Json object not found"};
8545 this.metaFromRemote = true;
8546 this.meta = o.metaData;
8547 this.recordType = Roo.data.Record.create(o.metaData.fields);
8548 this.onMetaChange(this.meta, this.recordType, o);
8550 return this.readRecords(o);
8553 // private function a store will implement
8554 onMetaChange : function(meta, recordType, o){
8561 simpleAccess: function(obj, subsc) {
8568 getJsonAccessor: function(){
8570 return function(expr) {
8572 return(re.test(expr))
8573 ? new Function("obj", "return obj." + expr)
8583 * Create a data block containing Roo.data.Records from an XML document.
8584 * @param {Object} o An object which contains an Array of row objects in the property specified
8585 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
8586 * which contains the total size of the dataset.
8587 * @return {Object} data A data block which is used by an Roo.data.Store object as
8588 * a cache of Roo.data.Records.
8590 readRecords : function(o){
8592 * After any data loads, the raw JSON data is available for further custom processing.
8596 var s = this.meta, Record = this.recordType,
8597 f = Record.prototype.fields, fi = f.items, fl = f.length;
8599 // Generate extraction functions for the totalProperty, the root, the id, and for each field
8601 if(s.totalProperty) {
8602 this.getTotal = this.getJsonAccessor(s.totalProperty);
8604 if(s.successProperty) {
8605 this.getSuccess = this.getJsonAccessor(s.successProperty);
8607 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
8609 var g = this.getJsonAccessor(s.id);
8610 this.getId = function(rec) {
8612 return (r === undefined || r === "") ? null : r;
8615 this.getId = function(){return null;};
8618 for(var jj = 0; jj < fl; jj++){
8620 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
8621 this.ef[jj] = this.getJsonAccessor(map);
8625 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
8626 if(s.totalProperty){
8627 var vt = parseInt(this.getTotal(o), 10);
8632 if(s.successProperty){
8633 var vs = this.getSuccess(o);
8634 if(vs === false || vs === 'false'){
8639 for(var i = 0; i < c; i++){
8642 var id = this.getId(n);
8643 for(var j = 0; j < fl; j++){
8645 var v = this.ef[j](n);
8647 Roo.log('missing convert for ' + f.name);
8651 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
8653 var record = new Record(values, id);
8655 records[i] = record;
8661 totalRecords : totalRecords
8666 * Ext JS Library 1.1.1
8667 * Copyright(c) 2006-2007, Ext JS, LLC.
8669 * Originally Released Under LGPL - original licence link has changed is not relivant.
8672 * <script type="text/javascript">
8676 * @class Roo.data.ArrayReader
8677 * @extends Roo.data.DataReader
8678 * Data reader class to create an Array of Roo.data.Record objects from an Array.
8679 * Each element of that Array represents a row of data fields. The
8680 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
8681 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
8685 var RecordDef = Roo.data.Record.create([
8686 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
8687 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
8689 var myReader = new Roo.data.ArrayReader({
8690 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
8694 * This would consume an Array like this:
8696 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
8698 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
8700 * Create a new JsonReader
8701 * @param {Object} meta Metadata configuration options.
8702 * @param {Object} recordType Either an Array of field definition objects
8703 * as specified to {@link Roo.data.Record#create},
8704 * or an {@link Roo.data.Record} object
8705 * created using {@link Roo.data.Record#create}.
8707 Roo.data.ArrayReader = function(meta, recordType){
8708 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
8711 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
8713 * Create a data block containing Roo.data.Records from an XML document.
8714 * @param {Object} o An Array of row objects which represents the dataset.
8715 * @return {Object} data A data block which is used by an Roo.data.Store object as
8716 * a cache of Roo.data.Records.
8718 readRecords : function(o){
8719 var sid = this.meta ? this.meta.id : null;
8720 var recordType = this.recordType, fields = recordType.prototype.fields;
8723 for(var i = 0; i < root.length; i++){
8726 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
8727 for(var j = 0, jlen = fields.length; j < jlen; j++){
8728 var f = fields.items[j];
8729 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
8730 var v = n[k] !== undefined ? n[k] : f.defaultValue;
8734 var record = new recordType(values, id);
8736 records[records.length] = record;
8740 totalRecords : records.length
8749 * @class Roo.bootstrap.ComboBox
8750 * @extends Roo.bootstrap.TriggerField
8751 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
8752 * @cfg {Boolean} append (true|false) default false
8754 * Create a new ComboBox.
8755 * @param {Object} config Configuration options
8757 Roo.bootstrap.ComboBox = function(config){
8758 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
8762 * Fires when the dropdown list is expanded
8763 * @param {Roo.bootstrap.ComboBox} combo This combo box
8768 * Fires when the dropdown list is collapsed
8769 * @param {Roo.bootstrap.ComboBox} combo This combo box
8773 * @event beforeselect
8774 * Fires before a list item is selected. Return false to cancel the selection.
8775 * @param {Roo.bootstrap.ComboBox} combo This combo box
8776 * @param {Roo.data.Record} record The data record returned from the underlying store
8777 * @param {Number} index The index of the selected item in the dropdown list
8779 'beforeselect' : true,
8782 * Fires when a list item is selected
8783 * @param {Roo.bootstrap.ComboBox} combo This combo box
8784 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
8785 * @param {Number} index The index of the selected item in the dropdown list
8789 * @event beforequery
8790 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
8791 * The event object passed has these properties:
8792 * @param {Roo.bootstrap.ComboBox} combo This combo box
8793 * @param {String} query The query
8794 * @param {Boolean} forceAll true to force "all" query
8795 * @param {Boolean} cancel true to cancel the query
8796 * @param {Object} e The query event object
8798 'beforequery': true,
8801 * Fires when the 'add' icon is pressed (add a listener to enable add button)
8802 * @param {Roo.bootstrap.ComboBox} combo This combo box
8807 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
8808 * @param {Roo.bootstrap.ComboBox} combo This combo box
8809 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
8814 * Fires when the remove value from the combobox array
8815 * @param {Roo.bootstrap.ComboBox} combo This combo box
8822 this.selectedIndex = -1;
8823 if(this.mode == 'local'){
8824 if(config.queryDelay === undefined){
8825 this.queryDelay = 10;
8827 if(config.minChars === undefined){
8833 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
8836 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
8837 * rendering into an Roo.Editor, defaults to false)
8840 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
8841 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
8844 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
8847 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
8848 * the dropdown list (defaults to undefined, with no header element)
8852 * @cfg {String/Roo.Template} tpl The template to use to render the output
8856 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
8858 listWidth: undefined,
8860 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
8861 * mode = 'remote' or 'text' if mode = 'local')
8863 displayField: undefined,
8865 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
8866 * mode = 'remote' or 'value' if mode = 'local').
8867 * Note: use of a valueField requires the user make a selection
8868 * in order for a value to be mapped.
8870 valueField: undefined,
8874 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
8875 * field's data value (defaults to the underlying DOM element's name)
8877 hiddenName: undefined,
8879 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
8883 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
8885 selectedClass: 'active',
8888 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
8892 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
8893 * anchor positions (defaults to 'tl-bl')
8895 listAlign: 'tl-bl?',
8897 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
8901 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
8902 * query specified by the allQuery config option (defaults to 'query')
8904 triggerAction: 'query',
8906 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
8907 * (defaults to 4, does not apply if editable = false)
8911 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
8912 * delay (typeAheadDelay) if it matches a known value (defaults to false)
8916 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
8917 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
8921 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
8922 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
8926 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
8927 * when editable = true (defaults to false)
8929 selectOnFocus:false,
8931 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
8933 queryParam: 'query',
8935 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
8936 * when mode = 'remote' (defaults to 'Loading...')
8938 loadingText: 'Loading...',
8940 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
8944 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
8948 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
8949 * traditional select (defaults to true)
8953 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
8957 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
8961 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
8962 * listWidth has a higher value)
8966 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
8967 * allow the user to set arbitrary text into the field (defaults to false)
8969 forceSelection:false,
8971 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
8972 * if typeAhead = true (defaults to 250)
8974 typeAheadDelay : 250,
8976 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
8977 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
8979 valueNotFoundText : undefined,
8981 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
8986 * @cfg {Boolean} disableClear Disable showing of clear button.
8988 disableClear : false,
8990 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
8992 alwaysQuery : false,
8995 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
9009 // element that contains real text value.. (when hidden is used..)
9012 initEvents: function(){
9015 throw "can not find store for combo";
9017 this.store = Roo.factory(this.store, Roo.data);
9021 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
9024 if(this.hiddenName){
9026 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
9028 this.hiddenField.dom.value =
9029 this.hiddenValue !== undefined ? this.hiddenValue :
9030 this.value !== undefined ? this.value : '';
9032 // prevent input submission
9033 this.el.dom.removeAttribute('name');
9034 this.hiddenField.dom.setAttribute('name', this.hiddenName);
9039 // this.el.dom.setAttribute('autocomplete', 'off');
9042 var cls = 'x-combo-list';
9043 this.list = this.el.select('ul.dropdown-menu',true).first();
9045 //this.list = new Roo.Layer({
9046 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
9049 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
9050 this.list.setWidth(lw);
9052 this.list.on('mouseover', this.onViewOver, this);
9053 this.list.on('mousemove', this.onViewMove, this);
9055 this.list.on('scroll', this.onViewScroll, this);
9058 this.list.swallowEvent('mousewheel');
9059 this.assetHeight = 0;
9062 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
9063 this.assetHeight += this.header.getHeight();
9066 this.innerList = this.list.createChild({cls:cls+'-inner'});
9067 this.innerList.on('mouseover', this.onViewOver, this);
9068 this.innerList.on('mousemove', this.onViewMove, this);
9069 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
9071 if(this.allowBlank && !this.pageSize && !this.disableClear){
9072 this.footer = this.list.createChild({cls:cls+'-ft'});
9073 this.pageTb = new Roo.Toolbar(this.footer);
9077 this.footer = this.list.createChild({cls:cls+'-ft'});
9078 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
9079 {pageSize: this.pageSize});
9083 if (this.pageTb && this.allowBlank && !this.disableClear) {
9085 this.pageTb.add(new Roo.Toolbar.Fill(), {
9086 cls: 'x-btn-icon x-btn-clear',
9092 _this.onSelect(false, -1);
9097 this.assetHeight += this.footer.getHeight();
9102 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
9105 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
9106 singleSelect:true, store: this.store, selectedClass: this.selectedClass
9108 //this.view.wrapEl.setDisplayed(false);
9109 this.view.on('click', this.onViewClick, this);
9113 this.store.on('beforeload', this.onBeforeLoad, this);
9114 this.store.on('load', this.onLoad, this);
9115 this.store.on('loadexception', this.onLoadException, this);
9118 this.resizer = new Roo.Resizable(this.list, {
9119 pinned:true, handles:'se'
9121 this.resizer.on('resize', function(r, w, h){
9122 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
9124 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
9125 this.restrictHeight();
9127 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
9131 this.editable = true;
9132 this.setEditable(false);
9137 if (typeof(this.events.add.listeners) != 'undefined') {
9139 this.addicon = this.wrap.createChild(
9140 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
9142 this.addicon.on('click', function(e) {
9143 this.fireEvent('add', this);
9146 if (typeof(this.events.edit.listeners) != 'undefined') {
9148 this.editicon = this.wrap.createChild(
9149 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
9151 this.editicon.setStyle('margin-left', '40px');
9153 this.editicon.on('click', function(e) {
9155 // we fire even if inothing is selected..
9156 this.fireEvent('edit', this, this.lastData );
9162 this.keyNav = new Roo.KeyNav(this.inputEl(), {
9164 this.inKeyMode = true;
9168 "down" : function(e){
9169 if(!this.isExpanded()){
9170 this.onTriggerClick();
9172 this.inKeyMode = true;
9177 "enter" : function(e){
9182 "esc" : function(e){
9186 "tab" : function(e){
9189 if(this.fireEvent("specialkey", this, e)){
9190 this.onViewClick(false);
9198 doRelay : function(foo, bar, hname){
9199 if(hname == 'down' || this.scope.isExpanded()){
9200 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
9209 this.queryDelay = Math.max(this.queryDelay || 10,
9210 this.mode == 'local' ? 10 : 250);
9213 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
9216 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
9218 if(this.editable !== false){
9219 this.inputEl().on("keyup", this.onKeyUp, this);
9221 if(this.forceSelection){
9222 this.on('blur', this.doForce, this);
9226 this.choices = this.el.select('ul.select2-choices', true).first();
9227 this.searchField = this.el.select('ul li.select2-search-field', true).first();
9231 onDestroy : function(){
9233 this.view.setStore(null);
9234 this.view.el.removeAllListeners();
9235 this.view.el.remove();
9236 this.view.purgeListeners();
9239 this.list.dom.innerHTML = '';
9242 this.store.un('beforeload', this.onBeforeLoad, this);
9243 this.store.un('load', this.onLoad, this);
9244 this.store.un('loadexception', this.onLoadException, this);
9246 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
9250 fireKey : function(e){
9251 if(e.isNavKeyPress() && !this.list.isVisible()){
9252 this.fireEvent("specialkey", this, e);
9257 onResize: function(w, h){
9258 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
9260 // if(typeof w != 'number'){
9261 // // we do not handle it!?!?
9264 // var tw = this.trigger.getWidth();
9265 // // tw += this.addicon ? this.addicon.getWidth() : 0;
9266 // // tw += this.editicon ? this.editicon.getWidth() : 0;
9268 // this.inputEl().setWidth( this.adjustWidth('input', x));
9270 // //this.trigger.setStyle('left', x+'px');
9272 // if(this.list && this.listWidth === undefined){
9273 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
9274 // this.list.setWidth(lw);
9275 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
9283 * Allow or prevent the user from directly editing the field text. If false is passed,
9284 * the user will only be able to select from the items defined in the dropdown list. This method
9285 * is the runtime equivalent of setting the 'editable' config option at config time.
9286 * @param {Boolean} value True to allow the user to directly edit the field text
9288 setEditable : function(value){
9289 if(value == this.editable){
9292 this.editable = value;
9294 this.inputEl().dom.setAttribute('readOnly', true);
9295 this.inputEl().on('mousedown', this.onTriggerClick, this);
9296 this.inputEl().addClass('x-combo-noedit');
9298 this.inputEl().dom.setAttribute('readOnly', false);
9299 this.inputEl().un('mousedown', this.onTriggerClick, this);
9300 this.inputEl().removeClass('x-combo-noedit');
9306 onBeforeLoad : function(combo,opts){
9311 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
9313 this.restrictHeight();
9314 this.selectedIndex = -1;
9318 onLoad : function(){
9320 this.hasQuery = false;
9326 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
9327 this.loading.hide();
9330 if(this.store.getCount() > 0){
9332 this.restrictHeight();
9333 if(this.lastQuery == this.allQuery){
9335 this.inputEl().dom.select();
9337 if(!this.selectByValue(this.value, true)){
9338 this.select(0, true);
9342 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
9343 this.taTask.delay(this.typeAheadDelay);
9347 this.onEmptyResults();
9353 onLoadException : function()
9355 this.hasQuery = false;
9357 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
9358 this.loading.hide();
9362 Roo.log(this.store.reader.jsonData);
9363 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
9365 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
9371 onTypeAhead : function(){
9372 if(this.store.getCount() > 0){
9373 var r = this.store.getAt(0);
9374 var newValue = r.data[this.displayField];
9375 var len = newValue.length;
9376 var selStart = this.getRawValue().length;
9378 if(selStart != len){
9379 this.setRawValue(newValue);
9380 this.selectText(selStart, newValue.length);
9386 onSelect : function(record, index){
9388 if(this.fireEvent('beforeselect', this, record, index) !== false){
9390 this.setFromData(index > -1 ? record.data : false);
9393 this.fireEvent('select', this, record, index);
9398 * Returns the currently selected field value or empty string if no value is set.
9399 * @return {String} value The selected value
9401 getValue : function(){
9404 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
9407 if(this.valueField){
9408 return typeof this.value != 'undefined' ? this.value : '';
9410 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
9415 * Clears any text/value currently set in the field
9417 clearValue : function(){
9418 if(this.hiddenField){
9419 this.hiddenField.dom.value = '';
9422 this.setRawValue('');
9423 this.lastSelectionText = '';
9428 * Sets the specified value into the field. If the value finds a match, the corresponding record text
9429 * will be displayed in the field. If the value does not match the data value of an existing item,
9430 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
9431 * Otherwise the field will be blank (although the value will still be set).
9432 * @param {String} value The value to match
9434 setValue : function(v){
9441 if(this.valueField){
9442 var r = this.findRecord(this.valueField, v);
9444 text = r.data[this.displayField];
9445 }else if(this.valueNotFoundText !== undefined){
9446 text = this.valueNotFoundText;
9449 this.lastSelectionText = text;
9450 if(this.hiddenField){
9451 this.hiddenField.dom.value = v;
9453 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
9457 * @property {Object} the last set data for the element
9462 * Sets the value of the field based on a object which is related to the record format for the store.
9463 * @param {Object} value the value to set as. or false on reset?
9465 setFromData : function(o){
9472 var dv = ''; // display value
9473 var vv = ''; // value value..
9475 if (this.displayField) {
9476 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
9478 // this is an error condition!!!
9479 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
9482 if(this.valueField){
9483 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
9486 if(this.hiddenField){
9487 this.hiddenField.dom.value = vv;
9489 this.lastSelectionText = dv;
9490 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
9494 // no hidden field.. - we store the value in 'value', but still display
9495 // display field!!!!
9496 this.lastSelectionText = dv;
9497 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
9504 // overridden so that last data is reset..
9505 this.setValue(this.originalValue);
9506 this.clearInvalid();
9507 this.lastData = false;
9509 this.view.clearSelections();
9513 findRecord : function(prop, value){
9515 if(this.store.getCount() > 0){
9516 this.store.each(function(r){
9517 if(r.data[prop] == value){
9529 // returns hidden if it's set..
9530 if (!this.rendered) {return ''};
9531 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
9535 onViewMove : function(e, t){
9536 this.inKeyMode = false;
9540 onViewOver : function(e, t){
9541 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
9544 var item = this.view.findItemFromChild(t);
9546 var index = this.view.indexOf(item);
9547 this.select(index, false);
9552 onViewClick : function(doFocus)
9554 var index = this.view.getSelectedIndexes()[0];
9555 var r = this.store.getAt(index);
9557 this.onSelect(r, index);
9559 if(doFocus !== false && !this.blockFocus){
9560 this.inputEl().focus();
9565 restrictHeight : function(){
9566 //this.innerList.dom.style.height = '';
9567 //var inner = this.innerList.dom;
9568 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
9569 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
9570 //this.list.beginUpdate();
9571 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
9572 this.list.alignTo(this.inputEl(), this.listAlign);
9573 //this.list.endUpdate();
9577 onEmptyResults : function(){
9582 * Returns true if the dropdown list is expanded, else false.
9584 isExpanded : function(){
9585 return this.list.isVisible();
9589 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
9590 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
9591 * @param {String} value The data value of the item to select
9592 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
9593 * selected item if it is not currently in view (defaults to true)
9594 * @return {Boolean} True if the value matched an item in the list, else false
9596 selectByValue : function(v, scrollIntoView){
9597 if(v !== undefined && v !== null){
9598 var r = this.findRecord(this.valueField || this.displayField, v);
9600 this.select(this.store.indexOf(r), scrollIntoView);
9608 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
9609 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
9610 * @param {Number} index The zero-based index of the list item to select
9611 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
9612 * selected item if it is not currently in view (defaults to true)
9614 select : function(index, scrollIntoView){
9615 this.selectedIndex = index;
9616 this.view.select(index);
9617 if(scrollIntoView !== false){
9618 var el = this.view.getNode(index);
9620 //this.innerList.scrollChildIntoView(el, false);
9627 selectNext : function(){
9628 var ct = this.store.getCount();
9630 if(this.selectedIndex == -1){
9632 }else if(this.selectedIndex < ct-1){
9633 this.select(this.selectedIndex+1);
9639 selectPrev : function(){
9640 var ct = this.store.getCount();
9642 if(this.selectedIndex == -1){
9644 }else if(this.selectedIndex != 0){
9645 this.select(this.selectedIndex-1);
9651 onKeyUp : function(e){
9652 if(this.editable !== false && !e.isSpecialKey()){
9653 this.lastKey = e.getKey();
9654 this.dqTask.delay(this.queryDelay);
9659 validateBlur : function(){
9660 return !this.list || !this.list.isVisible();
9664 initQuery : function(){
9665 this.doQuery(this.getRawValue());
9669 doForce : function(){
9670 if(this.el.dom.value.length > 0){
9672 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
9678 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
9679 * query allowing the query action to be canceled if needed.
9680 * @param {String} query The SQL query to execute
9681 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
9682 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
9683 * saved in the current store (defaults to false)
9685 doQuery : function(q, forceAll){
9687 if(q === undefined || q === null){
9696 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
9701 forceAll = qe.forceAll;
9702 if(forceAll === true || (q.length >= this.minChars)){
9704 this.hasQuery = true;
9706 if(this.lastQuery != q || this.alwaysQuery){
9708 if(this.mode == 'local'){
9709 this.selectedIndex = -1;
9711 this.store.clearFilter();
9713 this.store.filter(this.displayField, q);
9717 this.store.baseParams[this.queryParam] = q;
9719 var options = {params : this.getParams(q)};
9723 options.params.start = this.page * this.pageSize;
9726 this.store.load(options);
9730 this.selectedIndex = -1;
9735 this.loadNext = false;
9739 getParams : function(q){
9741 //p[this.queryParam] = q;
9745 p.limit = this.pageSize;
9751 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
9753 collapse : function(){
9754 if(!this.isExpanded()){
9759 Roo.get(document).un('mousedown', this.collapseIf, this);
9760 Roo.get(document).un('mousewheel', this.collapseIf, this);
9761 if (!this.editable) {
9762 Roo.get(document).un('keydown', this.listKeyPress, this);
9764 this.fireEvent('collapse', this);
9768 collapseIf : function(e){
9769 var in_combo = e.within(this.el);
9770 var in_list = e.within(this.list);
9772 if (in_combo || in_list) {
9773 //e.stopPropagation();
9782 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
9784 expand : function(){
9786 if(this.isExpanded() || !this.hasFocus){
9790 this.list.alignTo(this.inputEl(), this.listAlign);
9792 Roo.get(document).on('mousedown', this.collapseIf, this);
9793 Roo.get(document).on('mousewheel', this.collapseIf, this);
9794 if (!this.editable) {
9795 Roo.get(document).on('keydown', this.listKeyPress, this);
9798 this.fireEvent('expand', this);
9802 // Implements the default empty TriggerField.onTriggerClick function
9803 onTriggerClick : function()
9805 Roo.log('trigger click');
9812 this.loadNext = false;
9814 if(this.isExpanded()){
9816 if (!this.blockFocus) {
9817 this.inputEl().focus();
9821 this.hasFocus = true;
9822 if(this.triggerAction == 'all') {
9823 this.doQuery(this.allQuery, true);
9825 this.doQuery(this.getRawValue());
9827 if (!this.blockFocus) {
9828 this.inputEl().focus();
9832 listKeyPress : function(e)
9834 //Roo.log('listkeypress');
9835 // scroll to first matching element based on key pres..
9836 if (e.isSpecialKey()) {
9839 var k = String.fromCharCode(e.getKey()).toUpperCase();
9842 var csel = this.view.getSelectedNodes();
9843 var cselitem = false;
9845 var ix = this.view.indexOf(csel[0]);
9846 cselitem = this.store.getAt(ix);
9847 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
9853 this.store.each(function(v) {
9855 // start at existing selection.
9856 if (cselitem.id == v.id) {
9862 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
9863 match = this.store.indexOf(v);
9869 if (match === false) {
9870 return true; // no more action?
9873 this.view.select(match);
9874 var sn = Roo.get(this.view.getSelectedNodes()[0])
9875 //sn.scrollIntoView(sn.dom.parentNode, false);
9878 onViewScroll : function(e, t){
9880 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
9884 this.hasQuery = true;
9886 this.loading = this.list.select('.loading', true).first();
9888 if(this.loading === null){
9889 this.list.createChild({
9891 cls: 'loading select2-more-results select2-active',
9892 html: 'Loading more results...'
9895 this.loading = this.list.select('.loading', true).first();
9897 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
9899 this.loading.hide();
9902 this.loading.show();
9907 this.loadNext = true;
9909 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
9914 addItem : function(o)
9916 var dv = ''; // display value
9918 if (this.displayField) {
9919 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
9921 // this is an error condition!!!
9922 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
9929 var choice = this.choices.createChild({
9931 cls: 'select2-search-choice',
9940 cls: 'select2-search-choice-close',
9945 }, this.searchField);
9947 var close = choice.select('a.select2-search-choice-close', true).first()
9949 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
9956 this.inputEl().dom.value = '';
9960 onRemoveItem : function(e, _self, o)
9962 Roo.log('remove item');
9963 var index = this.item.indexOf(o.data) * 1;
9966 Roo.log('not this item?!');
9970 this.item.splice(index, 1);
9975 this.fireEvent('remove', this);
9979 syncValue : function()
9981 if(!this.item.length){
9988 Roo.each(this.item, function(i){
9989 if(_this.valueField){
9990 value.push(i[_this.valueField]);
9997 this.value = value.join(',');
9999 if(this.hiddenField){
10000 this.hiddenField.dom.value = this.value;
10004 clearItem : function()
10006 if(!this.multiple){
10012 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
10022 * @cfg {Boolean} grow
10026 * @cfg {Number} growMin
10030 * @cfg {Number} growMax
10040 * Ext JS Library 1.1.1
10041 * Copyright(c) 2006-2007, Ext JS, LLC.
10043 * Originally Released Under LGPL - original licence link has changed is not relivant.
10046 * <script type="text/javascript">
10051 * @extends Roo.util.Observable
10052 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
10053 * This class also supports single and multi selection modes. <br>
10054 * Create a data model bound view:
10056 var store = new Roo.data.Store(...);
10058 var view = new Roo.View({
10060 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
10062 singleSelect: true,
10063 selectedClass: "ydataview-selected",
10067 // listen for node click?
10068 view.on("click", function(vw, index, node, e){
10069 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
10073 dataModel.load("foobar.xml");
10075 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
10077 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
10078 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
10080 * Note: old style constructor is still suported (container, template, config)
10083 * Create a new View
10084 * @param {Object} config The config object
10087 Roo.View = function(config, depreciated_tpl, depreciated_config){
10089 if (typeof(depreciated_tpl) == 'undefined') {
10090 // new way.. - universal constructor.
10091 Roo.apply(this, config);
10092 this.el = Roo.get(this.el);
10095 this.el = Roo.get(config);
10096 this.tpl = depreciated_tpl;
10097 Roo.apply(this, depreciated_config);
10099 this.wrapEl = this.el.wrap().wrap();
10100 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
10103 if(typeof(this.tpl) == "string"){
10104 this.tpl = new Roo.Template(this.tpl);
10106 // support xtype ctors..
10107 this.tpl = new Roo.factory(this.tpl, Roo);
10111 this.tpl.compile();
10119 * @event beforeclick
10120 * Fires before a click is processed. Returns false to cancel the default action.
10121 * @param {Roo.View} this
10122 * @param {Number} index The index of the target node
10123 * @param {HTMLElement} node The target node
10124 * @param {Roo.EventObject} e The raw event object
10126 "beforeclick" : true,
10129 * Fires when a template node is clicked.
10130 * @param {Roo.View} this
10131 * @param {Number} index The index of the target node
10132 * @param {HTMLElement} node The target node
10133 * @param {Roo.EventObject} e The raw event object
10138 * Fires when a template node is double clicked.
10139 * @param {Roo.View} this
10140 * @param {Number} index The index of the target node
10141 * @param {HTMLElement} node The target node
10142 * @param {Roo.EventObject} e The raw event object
10146 * @event contextmenu
10147 * Fires when a template node is right clicked.
10148 * @param {Roo.View} this
10149 * @param {Number} index The index of the target node
10150 * @param {HTMLElement} node The target node
10151 * @param {Roo.EventObject} e The raw event object
10153 "contextmenu" : true,
10155 * @event selectionchange
10156 * Fires when the selected nodes change.
10157 * @param {Roo.View} this
10158 * @param {Array} selections Array of the selected nodes
10160 "selectionchange" : true,
10163 * @event beforeselect
10164 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
10165 * @param {Roo.View} this
10166 * @param {HTMLElement} node The node to be selected
10167 * @param {Array} selections Array of currently selected nodes
10169 "beforeselect" : true,
10171 * @event preparedata
10172 * Fires on every row to render, to allow you to change the data.
10173 * @param {Roo.View} this
10174 * @param {Object} data to be rendered (change this)
10176 "preparedata" : true
10184 "click": this.onClick,
10185 "dblclick": this.onDblClick,
10186 "contextmenu": this.onContextMenu,
10190 this.selections = [];
10192 this.cmp = new Roo.CompositeElementLite([]);
10194 this.store = Roo.factory(this.store, Roo.data);
10195 this.setStore(this.store, true);
10198 if ( this.footer && this.footer.xtype) {
10200 var fctr = this.wrapEl.appendChild(document.createElement("div"));
10202 this.footer.dataSource = this.store
10203 this.footer.container = fctr;
10204 this.footer = Roo.factory(this.footer, Roo);
10205 fctr.insertFirst(this.el);
10207 // this is a bit insane - as the paging toolbar seems to detach the el..
10208 // dom.parentNode.parentNode.parentNode
10209 // they get detached?
10213 Roo.View.superclass.constructor.call(this);
10218 Roo.extend(Roo.View, Roo.util.Observable, {
10221 * @cfg {Roo.data.Store} store Data store to load data from.
10226 * @cfg {String|Roo.Element} el The container element.
10231 * @cfg {String|Roo.Template} tpl The template used by this View
10235 * @cfg {String} dataName the named area of the template to use as the data area
10236 * Works with domtemplates roo-name="name"
10240 * @cfg {String} selectedClass The css class to add to selected nodes
10242 selectedClass : "x-view-selected",
10244 * @cfg {String} emptyText The empty text to show when nothing is loaded.
10249 * @cfg {String} text to display on mask (default Loading)
10253 * @cfg {Boolean} multiSelect Allow multiple selection
10255 multiSelect : false,
10257 * @cfg {Boolean} singleSelect Allow single selection
10259 singleSelect: false,
10262 * @cfg {Boolean} toggleSelect - selecting
10264 toggleSelect : false,
10267 * Returns the element this view is bound to.
10268 * @return {Roo.Element}
10270 getEl : function(){
10271 return this.wrapEl;
10277 * Refreshes the view. - called by datachanged on the store. - do not call directly.
10279 refresh : function(){
10280 Roo.log('refresh');
10283 // if we are using something like 'domtemplate', then
10284 // the what gets used is:
10285 // t.applySubtemplate(NAME, data, wrapping data..)
10286 // the outer template then get' applied with
10287 // the store 'extra data'
10288 // and the body get's added to the
10289 // roo-name="data" node?
10290 // <span class='roo-tpl-{name}'></span> ?????
10294 this.clearSelections();
10295 this.el.update("");
10297 var records = this.store.getRange();
10298 if(records.length < 1) {
10300 // is this valid?? = should it render a template??
10302 this.el.update(this.emptyText);
10306 if (this.dataName) {
10307 this.el.update(t.apply(this.store.meta)); //????
10308 el = this.el.child('.roo-tpl-' + this.dataName);
10311 for(var i = 0, len = records.length; i < len; i++){
10312 var data = this.prepareData(records[i].data, i, records[i]);
10313 this.fireEvent("preparedata", this, data, i, records[i]);
10314 html[html.length] = Roo.util.Format.trim(
10316 t.applySubtemplate(this.dataName, data, this.store.meta) :
10323 el.update(html.join(""));
10324 this.nodes = el.dom.childNodes;
10325 this.updateIndexes(0);
10330 * Function to override to reformat the data that is sent to
10331 * the template for each node.
10332 * DEPRICATED - use the preparedata event handler.
10333 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
10334 * a JSON object for an UpdateManager bound view).
10336 prepareData : function(data, index, record)
10338 this.fireEvent("preparedata", this, data, index, record);
10342 onUpdate : function(ds, record){
10343 Roo.log('on update');
10344 this.clearSelections();
10345 var index = this.store.indexOf(record);
10346 var n = this.nodes[index];
10347 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
10348 n.parentNode.removeChild(n);
10349 this.updateIndexes(index, index);
10355 onAdd : function(ds, records, index)
10357 Roo.log(['on Add', ds, records, index] );
10358 this.clearSelections();
10359 if(this.nodes.length == 0){
10363 var n = this.nodes[index];
10364 for(var i = 0, len = records.length; i < len; i++){
10365 var d = this.prepareData(records[i].data, i, records[i]);
10367 this.tpl.insertBefore(n, d);
10370 this.tpl.append(this.el, d);
10373 this.updateIndexes(index);
10376 onRemove : function(ds, record, index){
10377 Roo.log('onRemove');
10378 this.clearSelections();
10379 var el = this.dataName ?
10380 this.el.child('.roo-tpl-' + this.dataName) :
10383 el.dom.removeChild(this.nodes[index]);
10384 this.updateIndexes(index);
10388 * Refresh an individual node.
10389 * @param {Number} index
10391 refreshNode : function(index){
10392 this.onUpdate(this.store, this.store.getAt(index));
10395 updateIndexes : function(startIndex, endIndex){
10396 var ns = this.nodes;
10397 startIndex = startIndex || 0;
10398 endIndex = endIndex || ns.length - 1;
10399 for(var i = startIndex; i <= endIndex; i++){
10400 ns[i].nodeIndex = i;
10405 * Changes the data store this view uses and refresh the view.
10406 * @param {Store} store
10408 setStore : function(store, initial){
10409 if(!initial && this.store){
10410 this.store.un("datachanged", this.refresh);
10411 this.store.un("add", this.onAdd);
10412 this.store.un("remove", this.onRemove);
10413 this.store.un("update", this.onUpdate);
10414 this.store.un("clear", this.refresh);
10415 this.store.un("beforeload", this.onBeforeLoad);
10416 this.store.un("load", this.onLoad);
10417 this.store.un("loadexception", this.onLoad);
10421 store.on("datachanged", this.refresh, this);
10422 store.on("add", this.onAdd, this);
10423 store.on("remove", this.onRemove, this);
10424 store.on("update", this.onUpdate, this);
10425 store.on("clear", this.refresh, this);
10426 store.on("beforeload", this.onBeforeLoad, this);
10427 store.on("load", this.onLoad, this);
10428 store.on("loadexception", this.onLoad, this);
10436 * onbeforeLoad - masks the loading area.
10439 onBeforeLoad : function(store,opts)
10441 Roo.log('onBeforeLoad');
10443 this.el.update("");
10445 this.el.mask(this.mask ? this.mask : "Loading" );
10447 onLoad : function ()
10454 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
10455 * @param {HTMLElement} node
10456 * @return {HTMLElement} The template node
10458 findItemFromChild : function(node){
10459 var el = this.dataName ?
10460 this.el.child('.roo-tpl-' + this.dataName,true) :
10463 if(!node || node.parentNode == el){
10466 var p = node.parentNode;
10467 while(p && p != el){
10468 if(p.parentNode == el){
10477 onClick : function(e){
10478 var item = this.findItemFromChild(e.getTarget());
10480 var index = this.indexOf(item);
10481 if(this.onItemClick(item, index, e) !== false){
10482 this.fireEvent("click", this, index, item, e);
10485 this.clearSelections();
10490 onContextMenu : function(e){
10491 var item = this.findItemFromChild(e.getTarget());
10493 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
10498 onDblClick : function(e){
10499 var item = this.findItemFromChild(e.getTarget());
10501 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
10505 onItemClick : function(item, index, e)
10507 if(this.fireEvent("beforeclick", this, index, item, e) === false){
10510 if (this.toggleSelect) {
10511 var m = this.isSelected(item) ? 'unselect' : 'select';
10514 _t[m](item, true, false);
10517 if(this.multiSelect || this.singleSelect){
10518 if(this.multiSelect && e.shiftKey && this.lastSelection){
10519 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
10521 this.select(item, this.multiSelect && e.ctrlKey);
10522 this.lastSelection = item;
10524 e.preventDefault();
10530 * Get the number of selected nodes.
10533 getSelectionCount : function(){
10534 return this.selections.length;
10538 * Get the currently selected nodes.
10539 * @return {Array} An array of HTMLElements
10541 getSelectedNodes : function(){
10542 return this.selections;
10546 * Get the indexes of the selected nodes.
10549 getSelectedIndexes : function(){
10550 var indexes = [], s = this.selections;
10551 for(var i = 0, len = s.length; i < len; i++){
10552 indexes.push(s[i].nodeIndex);
10558 * Clear all selections
10559 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
10561 clearSelections : function(suppressEvent){
10562 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
10563 this.cmp.elements = this.selections;
10564 this.cmp.removeClass(this.selectedClass);
10565 this.selections = [];
10566 if(!suppressEvent){
10567 this.fireEvent("selectionchange", this, this.selections);
10573 * Returns true if the passed node is selected
10574 * @param {HTMLElement/Number} node The node or node index
10575 * @return {Boolean}
10577 isSelected : function(node){
10578 var s = this.selections;
10582 node = this.getNode(node);
10583 return s.indexOf(node) !== -1;
10588 * @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
10589 * @param {Boolean} keepExisting (optional) true to keep existing selections
10590 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
10592 select : function(nodeInfo, keepExisting, suppressEvent){
10593 if(nodeInfo instanceof Array){
10595 this.clearSelections(true);
10597 for(var i = 0, len = nodeInfo.length; i < len; i++){
10598 this.select(nodeInfo[i], true, true);
10602 var node = this.getNode(nodeInfo);
10603 if(!node || this.isSelected(node)){
10604 return; // already selected.
10607 this.clearSelections(true);
10609 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
10610 Roo.fly(node).addClass(this.selectedClass);
10611 this.selections.push(node);
10612 if(!suppressEvent){
10613 this.fireEvent("selectionchange", this, this.selections);
10621 * @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
10622 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
10623 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
10625 unselect : function(nodeInfo, keepExisting, suppressEvent)
10627 if(nodeInfo instanceof Array){
10628 Roo.each(this.selections, function(s) {
10629 this.unselect(s, nodeInfo);
10633 var node = this.getNode(nodeInfo);
10634 if(!node || !this.isSelected(node)){
10635 Roo.log("not selected");
10636 return; // not selected.
10640 Roo.each(this.selections, function(s) {
10642 Roo.fly(node).removeClass(this.selectedClass);
10649 this.selections= ns;
10650 this.fireEvent("selectionchange", this, this.selections);
10654 * Gets a template node.
10655 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
10656 * @return {HTMLElement} The node or null if it wasn't found
10658 getNode : function(nodeInfo){
10659 if(typeof nodeInfo == "string"){
10660 return document.getElementById(nodeInfo);
10661 }else if(typeof nodeInfo == "number"){
10662 return this.nodes[nodeInfo];
10668 * Gets a range template nodes.
10669 * @param {Number} startIndex
10670 * @param {Number} endIndex
10671 * @return {Array} An array of nodes
10673 getNodes : function(start, end){
10674 var ns = this.nodes;
10675 start = start || 0;
10676 end = typeof end == "undefined" ? ns.length - 1 : end;
10679 for(var i = start; i <= end; i++){
10683 for(var i = start; i >= end; i--){
10691 * Finds the index of the passed node
10692 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
10693 * @return {Number} The index of the node or -1
10695 indexOf : function(node){
10696 node = this.getNode(node);
10697 if(typeof node.nodeIndex == "number"){
10698 return node.nodeIndex;
10700 var ns = this.nodes;
10701 for(var i = 0, len = ns.length; i < len; i++){
10712 * based on jquery fullcalendar
10716 Roo.bootstrap = Roo.bootstrap || {};
10718 * @class Roo.bootstrap.Calendar
10719 * @extends Roo.bootstrap.Component
10720 * Bootstrap Calendar class
10721 * @cfg {Boolean} loadMask (true|false) default false
10722 * @cfg {Object} header generate the user specific header of the calendar, default false
10725 * Create a new Container
10726 * @param {Object} config The config object
10731 Roo.bootstrap.Calendar = function(config){
10732 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
10736 * Fires when a date is selected
10737 * @param {DatePicker} this
10738 * @param {Date} date The selected date
10742 * @event monthchange
10743 * Fires when the displayed month changes
10744 * @param {DatePicker} this
10745 * @param {Date} date The selected month
10747 'monthchange': true,
10749 * @event evententer
10750 * Fires when mouse over an event
10751 * @param {Calendar} this
10752 * @param {event} Event
10754 'evententer': true,
10756 * @event eventleave
10757 * Fires when the mouse leaves an
10758 * @param {Calendar} this
10761 'eventleave': true,
10763 * @event eventclick
10764 * Fires when the mouse click an
10765 * @param {Calendar} this
10774 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
10777 * @cfg {Number} startDay
10778 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
10786 getAutoCreate : function(){
10789 var fc_button = function(name, corner, style, content ) {
10790 return Roo.apply({},{
10792 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
10794 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
10797 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
10808 style : 'width:100%',
10815 cls : 'fc-header-left',
10817 fc_button('prev', 'left', 'arrow', '‹' ),
10818 fc_button('next', 'right', 'arrow', '›' ),
10819 { tag: 'span', cls: 'fc-header-space' },
10820 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
10828 cls : 'fc-header-center',
10832 cls: 'fc-header-title',
10835 html : 'month / year'
10843 cls : 'fc-header-right',
10845 /* fc_button('month', 'left', '', 'month' ),
10846 fc_button('week', '', '', 'week' ),
10847 fc_button('day', 'right', '', 'day' )
10859 header = this.header;
10862 var cal_heads = function() {
10864 // fixme - handle this.
10866 for (var i =0; i < Date.dayNames.length; i++) {
10867 var d = Date.dayNames[i];
10870 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
10871 html : d.substring(0,3)
10875 ret[0].cls += ' fc-first';
10876 ret[6].cls += ' fc-last';
10879 var cal_cell = function(n) {
10882 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
10887 cls: 'fc-day-number',
10891 cls: 'fc-day-content',
10895 style: 'position: relative;' // height: 17px;
10907 var cal_rows = function() {
10910 for (var r = 0; r < 6; r++) {
10917 for (var i =0; i < Date.dayNames.length; i++) {
10918 var d = Date.dayNames[i];
10919 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
10922 row.cn[0].cls+=' fc-first';
10923 row.cn[0].cn[0].style = 'min-height:90px';
10924 row.cn[6].cls+=' fc-last';
10928 ret[0].cls += ' fc-first';
10929 ret[4].cls += ' fc-prev-last';
10930 ret[5].cls += ' fc-last';
10937 cls: 'fc-border-separate',
10938 style : 'width:100%',
10946 cls : 'fc-first fc-last',
10964 cls : 'fc-content',
10965 style : "position: relative;",
10968 cls : 'fc-view fc-view-month fc-grid',
10969 style : 'position: relative',
10970 unselectable : 'on',
10973 cls : 'fc-event-container',
10974 style : 'position:absolute;z-index:8;top:0;left:0;'
10992 initEvents : function()
10995 throw "can not find store for calendar";
11001 style: "text-align:center",
11005 style: "background-color:white;width:50%;margin:250 auto",
11009 src: rootURL + '/roojs1/images/ux/lightbox/loading.gif'
11020 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
11022 var size = this.el.select('.fc-content', true).first().getSize();
11023 this.maskEl.setSize(size.width, size.height);
11024 this.maskEl.enableDisplayMode("block");
11025 if(!this.loadMask){
11026 this.maskEl.hide();
11029 this.store = Roo.factory(this.store, Roo.data);
11030 this.store.on('load', this.onLoad, this);
11031 this.store.on('beforeload', this.onBeforeLoad, this);
11035 this.cells = this.el.select('.fc-day',true);
11036 //Roo.log(this.cells);
11037 this.textNodes = this.el.query('.fc-day-number');
11038 this.cells.addClassOnOver('fc-state-hover');
11040 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
11041 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
11042 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
11043 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
11045 this.on('monthchange', this.onMonthChange, this);
11047 this.update(new Date().clearTime());
11050 resize : function() {
11051 var sz = this.el.getSize();
11053 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
11054 this.el.select('.fc-day-content div',true).setHeight(34);
11059 showPrevMonth : function(e){
11060 this.update(this.activeDate.add("mo", -1));
11062 showToday : function(e){
11063 this.update(new Date().clearTime());
11066 showNextMonth : function(e){
11067 this.update(this.activeDate.add("mo", 1));
11071 showPrevYear : function(){
11072 this.update(this.activeDate.add("y", -1));
11076 showNextYear : function(){
11077 this.update(this.activeDate.add("y", 1));
11082 update : function(date)
11084 var vd = this.activeDate;
11085 this.activeDate = date;
11086 // if(vd && this.el){
11087 // var t = date.getTime();
11088 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
11089 // Roo.log('using add remove');
11091 // this.fireEvent('monthchange', this, date);
11093 // this.cells.removeClass("fc-state-highlight");
11094 // this.cells.each(function(c){
11095 // if(c.dateValue == t){
11096 // c.addClass("fc-state-highlight");
11097 // setTimeout(function(){
11098 // try{c.dom.firstChild.focus();}catch(e){}
11108 var days = date.getDaysInMonth();
11110 var firstOfMonth = date.getFirstDateOfMonth();
11111 var startingPos = firstOfMonth.getDay()-this.startDay;
11113 if(startingPos < this.startDay){
11117 var pm = date.add(Date.MONTH, -1);
11118 var prevStart = pm.getDaysInMonth()-startingPos;
11120 this.cells = this.el.select('.fc-day',true);
11121 this.textNodes = this.el.query('.fc-day-number');
11122 this.cells.addClassOnOver('fc-state-hover');
11124 var cells = this.cells.elements;
11125 var textEls = this.textNodes;
11127 Roo.each(cells, function(cell){
11128 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
11131 days += startingPos;
11133 // convert everything to numbers so it's fast
11134 var day = 86400000;
11135 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
11138 //Roo.log(prevStart);
11140 var today = new Date().clearTime().getTime();
11141 var sel = date.clearTime().getTime();
11142 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
11143 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
11144 var ddMatch = this.disabledDatesRE;
11145 var ddText = this.disabledDatesText;
11146 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
11147 var ddaysText = this.disabledDaysText;
11148 var format = this.format;
11150 var setCellClass = function(cal, cell){
11152 //Roo.log('set Cell Class');
11154 var t = d.getTime();
11158 cell.dateValue = t;
11160 cell.className += " fc-today";
11161 cell.className += " fc-state-highlight";
11162 cell.title = cal.todayText;
11165 // disable highlight in other month..
11166 //cell.className += " fc-state-highlight";
11171 cell.className = " fc-state-disabled";
11172 cell.title = cal.minText;
11176 cell.className = " fc-state-disabled";
11177 cell.title = cal.maxText;
11181 if(ddays.indexOf(d.getDay()) != -1){
11182 cell.title = ddaysText;
11183 cell.className = " fc-state-disabled";
11186 if(ddMatch && format){
11187 var fvalue = d.dateFormat(format);
11188 if(ddMatch.test(fvalue)){
11189 cell.title = ddText.replace("%0", fvalue);
11190 cell.className = " fc-state-disabled";
11194 if (!cell.initialClassName) {
11195 cell.initialClassName = cell.dom.className;
11198 cell.dom.className = cell.initialClassName + ' ' + cell.className;
11203 for(; i < startingPos; i++) {
11204 textEls[i].innerHTML = (++prevStart);
11205 d.setDate(d.getDate()+1);
11207 cells[i].className = "fc-past fc-other-month";
11208 setCellClass(this, cells[i]);
11213 for(; i < days; i++){
11214 intDay = i - startingPos + 1;
11215 textEls[i].innerHTML = (intDay);
11216 d.setDate(d.getDate()+1);
11218 cells[i].className = ''; // "x-date-active";
11219 setCellClass(this, cells[i]);
11223 for(; i < 42; i++) {
11224 textEls[i].innerHTML = (++extraDays);
11225 d.setDate(d.getDate()+1);
11227 cells[i].className = "fc-future fc-other-month";
11228 setCellClass(this, cells[i]);
11231 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
11233 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
11235 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
11236 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
11238 if(totalRows != 6){
11239 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
11240 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
11243 this.fireEvent('monthchange', this, date);
11247 if(!this.internalRender){
11248 var main = this.el.dom.firstChild;
11249 var w = main.offsetWidth;
11250 this.el.setWidth(w + this.el.getBorderWidth("lr"));
11251 Roo.fly(main).setWidth(w);
11252 this.internalRender = true;
11253 // opera does not respect the auto grow header center column
11254 // then, after it gets a width opera refuses to recalculate
11255 // without a second pass
11256 if(Roo.isOpera && !this.secondPass){
11257 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
11258 this.secondPass = true;
11259 this.update.defer(10, this, [date]);
11266 findCell : function(dt) {
11267 dt = dt.clearTime().getTime();
11269 this.cells.each(function(c){
11270 //Roo.log("check " +c.dateValue + '?=' + dt);
11271 if(c.dateValue == dt){
11281 findCells : function(ev) {
11282 var s = ev.start.clone().clearTime().getTime();
11284 var e= ev.end.clone().clearTime().getTime();
11287 this.cells.each(function(c){
11288 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
11290 if(c.dateValue > e){
11293 if(c.dateValue < s){
11302 findBestRow: function(cells)
11306 for (var i =0 ; i < cells.length;i++) {
11307 ret = Math.max(cells[i].rows || 0,ret);
11314 addItem : function(ev)
11316 // look for vertical location slot in
11317 var cells = this.findCells(ev);
11319 ev.row = this.findBestRow(cells);
11321 // work out the location.
11325 for(var i =0; i < cells.length; i++) {
11333 if (crow.start.getY() == cells[i].getY()) {
11335 crow.end = cells[i];
11351 for (var i = 0; i < cells.length;i++) {
11352 cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
11356 this.calevents.push(ev);
11359 clearEvents: function() {
11361 if(!this.calevents){
11365 Roo.each(this.cells.elements, function(c){
11369 Roo.each(this.calevents, function(e) {
11370 Roo.each(e.els, function(el) {
11371 el.un('mouseenter' ,this.onEventEnter, this);
11372 el.un('mouseleave' ,this.onEventLeave, this);
11379 renderEvents: function()
11381 // first make sure there is enough space..
11383 this.cells.each(function(c) {
11385 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.rows * 20));
11388 for (var e = 0; e < this.calevents.length; e++) {
11389 var ev = this.calevents[e];
11390 var cells = ev.cells;
11391 var rows = ev.rows;
11393 for(var i =0; i < rows.length; i++) {
11396 // how many rows should it span..
11399 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
11400 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
11402 unselectable : "on",
11405 cls: 'fc-event-inner',
11409 // cls: 'fc-event-time',
11410 // html : cells.length > 1 ? '' : ev.time
11414 cls: 'fc-event-title',
11415 html : String.format('{0}', ev.title)
11422 cls: 'ui-resizable-handle ui-resizable-e',
11423 html : '  '
11429 cfg.cls += ' fc-event-start';
11431 if ((i+1) == rows.length) {
11432 cfg.cls += ' fc-event-end';
11435 var ctr = this.el.select('.fc-event-container',true).first();
11436 var cg = ctr.createChild(cfg);
11438 cg.on('mouseenter' ,this.onEventEnter, this, ev);
11439 cg.on('mouseleave' ,this.onEventLeave, this, ev);
11440 cg.on('click', this.onEventClick, this, ev);
11444 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
11445 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
11447 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
11448 cg.setWidth(ebox.right - sbox.x -2);
11456 onEventEnter: function (e, el,event,d) {
11457 this.fireEvent('evententer', this, el, event);
11460 onEventLeave: function (e, el,event,d) {
11461 this.fireEvent('eventleave', this, el, event);
11464 onEventClick: function (e, el,event,d) {
11465 this.fireEvent('eventclick', this, el, event);
11468 onMonthChange: function () {
11472 onLoad: function ()
11474 this.calevents = [];
11477 if(this.store.getCount() > 0){
11478 this.store.data.each(function(d){
11481 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
11482 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
11483 time : d.data.start_time,
11484 title : d.data.title,
11485 description : d.data.description,
11486 venue : d.data.venue
11491 this.renderEvents();
11494 this.maskEl.hide();
11498 onBeforeLoad: function()
11500 this.clearEvents();
11503 this.maskEl.show();
11517 * @class Roo.bootstrap.Popover
11518 * @extends Roo.bootstrap.Component
11519 * Bootstrap Popover class
11520 * @cfg {String} html contents of the popover (or false to use children..)
11521 * @cfg {String} title of popover (or false to hide)
11522 * @cfg {String} placement how it is placed
11523 * @cfg {String} trigger click || hover (or false to trigger manually)
11524 * @cfg {String} over what (parent or false to trigger manually.)
11527 * Create a new Popover
11528 * @param {Object} config The config object
11531 Roo.bootstrap.Popover = function(config){
11532 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
11535 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
11537 title: 'Fill in a title',
11540 placement : 'right',
11541 trigger : 'hover', // hover
11545 can_build_overlaid : false,
11547 getChildContainer : function()
11549 return this.el.select('.popover-content',true).first();
11552 getAutoCreate : function(){
11553 Roo.log('make popover?');
11555 cls : 'popover roo-dynamic',
11556 style: 'display:block',
11562 cls : 'popover-inner',
11566 cls: 'popover-title',
11570 cls : 'popover-content',
11581 setTitle: function(str)
11583 this.el.select('.popover-title',true).first().dom.innerHTML = str;
11585 setContent: function(str)
11587 this.el.select('.popover-content',true).first().dom.innerHTML = str;
11589 // as it get's added to the bottom of the page.
11590 onRender : function(ct, position)
11592 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
11594 var cfg = Roo.apply({}, this.getAutoCreate());
11598 cfg.cls += ' ' + this.cls;
11601 cfg.style = this.style;
11603 Roo.log("adding to ")
11604 this.el = Roo.get(document.body).createChild(cfg, position);
11610 initEvents : function()
11612 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
11613 this.el.enableDisplayMode('block');
11615 if (this.over === false) {
11618 if (this.triggers === false) {
11621 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
11622 var triggers = this.trigger ? this.trigger.split(' ') : [];
11623 Roo.each(triggers, function(trigger) {
11625 if (trigger == 'click') {
11626 on_el.on('click', this.toggle, this);
11627 } else if (trigger != 'manual') {
11628 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
11629 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
11631 on_el.on(eventIn ,this.enter, this);
11632 on_el.on(eventOut, this.leave, this);
11643 toggle : function () {
11644 this.hoverState == 'in' ? this.leave() : this.enter();
11647 enter : function () {
11650 clearTimeout(this.timeout);
11652 this.hoverState = 'in'
11654 if (!this.delay || !this.delay.show) {
11659 this.timeout = setTimeout(function () {
11660 if (_t.hoverState == 'in') {
11663 }, this.delay.show)
11665 leave : function() {
11666 clearTimeout(this.timeout);
11668 this.hoverState = 'out'
11670 if (!this.delay || !this.delay.hide) {
11675 this.timeout = setTimeout(function () {
11676 if (_t.hoverState == 'out') {
11679 }, this.delay.hide)
11682 show : function (on_el)
11685 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
11688 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
11689 if (this.html !== false) {
11690 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
11692 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
11693 if (!this.title.length) {
11694 this.el.select('.popover-title',true).hide();
11697 var placement = typeof this.placement == 'function' ?
11698 this.placement.call(this, this.el, on_el) :
11701 var autoToken = /\s?auto?\s?/i;
11702 var autoPlace = autoToken.test(placement);
11704 placement = placement.replace(autoToken, '') || 'top';
11708 //this.el.setXY([0,0]);
11710 this.el.dom.style.display='block';
11711 this.el.addClass(placement);
11713 //this.el.appendTo(on_el);
11715 var p = this.getPosition();
11716 var box = this.el.getBox();
11721 var align = Roo.bootstrap.Popover.alignment[placement]
11722 this.el.alignTo(on_el, align[0],align[1]);
11723 //var arrow = this.el.select('.arrow',true).first();
11724 //arrow.set(align[2],
11726 this.el.addClass('in');
11727 this.hoverState = null;
11729 if (this.el.hasClass('fade')) {
11736 this.el.setXY([0,0]);
11737 this.el.removeClass('in');
11744 Roo.bootstrap.Popover.alignment = {
11745 'left' : ['r-l', [-10,0], 'right'],
11746 'right' : ['l-r', [10,0], 'left'],
11747 'bottom' : ['t-b', [0,10], 'top'],
11748 'top' : [ 'b-t', [0,-10], 'bottom']
11759 * @class Roo.bootstrap.Progress
11760 * @extends Roo.bootstrap.Component
11761 * Bootstrap Progress class
11762 * @cfg {Boolean} striped striped of the progress bar
11763 * @cfg {Boolean} active animated of the progress bar
11767 * Create a new Progress
11768 * @param {Object} config The config object
11771 Roo.bootstrap.Progress = function(config){
11772 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
11775 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
11780 getAutoCreate : function(){
11788 cfg.cls += ' progress-striped';
11792 cfg.cls += ' active';
11811 * @class Roo.bootstrap.ProgressBar
11812 * @extends Roo.bootstrap.Component
11813 * Bootstrap ProgressBar class
11814 * @cfg {Number} aria_valuenow aria-value now
11815 * @cfg {Number} aria_valuemin aria-value min
11816 * @cfg {Number} aria_valuemax aria-value max
11817 * @cfg {String} label label for the progress bar
11818 * @cfg {String} panel (success | info | warning | danger )
11819 * @cfg {String} role role of the progress bar
11820 * @cfg {String} sr_only text
11824 * Create a new ProgressBar
11825 * @param {Object} config The config object
11828 Roo.bootstrap.ProgressBar = function(config){
11829 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
11832 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
11836 aria_valuemax : 100,
11842 getAutoCreate : function()
11847 cls: 'progress-bar',
11848 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
11860 cfg.role = this.role;
11863 if(this.aria_valuenow){
11864 cfg['aria-valuenow'] = this.aria_valuenow;
11867 if(this.aria_valuemin){
11868 cfg['aria-valuemin'] = this.aria_valuemin;
11871 if(this.aria_valuemax){
11872 cfg['aria-valuemax'] = this.aria_valuemax;
11875 if(this.label && !this.sr_only){
11876 cfg.html = this.label;
11880 cfg.cls += ' progress-bar-' + this.panel;
11886 update : function(aria_valuenow)
11888 this.aria_valuenow = aria_valuenow;
11890 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
11905 * @class Roo.bootstrap.TabPanel
11906 * @extends Roo.bootstrap.Component
11907 * Bootstrap TabPanel class
11908 * @cfg {Boolean} active panel active
11909 * @cfg {String} html panel content
11910 * @cfg {String} tabId tab relate id
11911 * @cfg {String} navId The navbar which triggers show hide
11915 * Create a new TabPanel
11916 * @param {Object} config The config object
11919 Roo.bootstrap.TabPanel = function(config){
11920 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
11924 * Fires when the active status changes
11925 * @param {Roo.bootstrap.TabPanel} this
11926 * @param {Boolean} state the new state
11933 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
11940 getAutoCreate : function(){
11944 html: this.html || ''
11948 cfg.cls += ' active';
11952 cfg.tabId = this.tabId;
11957 onRender : function(ct, position)
11959 // Roo.log("Call onRender: " + this.xtype);
11961 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
11963 if (this.navId && this.tabId) {
11964 var item = Roo.bootstrap.NavGroup.get(this.navId).getNavItem(this.tabId);
11966 Roo.log("could not find navID:" + this.navId + ", tabId: " + this.tabId);
11968 item.on('changed', function(item, state) {
11969 this.setActive(state);
11975 setActive: function(state)
11977 Roo.log("panel - set active " + this.tabId + "=" + state);
11979 this.active = state;
11981 this.el.removeClass('active');
11983 } else if (!this.el.hasClass('active')) {
11984 this.el.addClass('active');
11986 this.fireEvent('changed', this, state);
12003 * @class Roo.bootstrap.DateField
12004 * @extends Roo.bootstrap.Input
12005 * Bootstrap DateField class
12006 * @cfg {Number} weekStart default 0
12007 * @cfg {Number} weekStart default 0
12008 * @cfg {Number} viewMode default empty, (months|years)
12009 * @cfg {Number} minViewMode default empty, (months|years)
12010 * @cfg {Number} startDate default -Infinity
12011 * @cfg {Number} endDate default Infinity
12012 * @cfg {Boolean} todayHighlight default false
12013 * @cfg {Boolean} todayBtn default false
12014 * @cfg {Boolean} calendarWeeks default false
12015 * @cfg {Object} daysOfWeekDisabled default empty
12017 * @cfg {Boolean} keyboardNavigation default true
12018 * @cfg {String} language default en
12021 * Create a new DateField
12022 * @param {Object} config The config object
12025 Roo.bootstrap.DateField = function(config){
12026 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
12030 * Fires when this field show.
12031 * @param {Roo.bootstrap.DateField} this
12032 * @param {Mixed} date The date value
12037 * Fires when this field hide.
12038 * @param {Roo.bootstrap.DateField} this
12039 * @param {Mixed} date The date value
12044 * Fires when select a date.
12045 * @param {Roo.bootstrap.DateField} this
12046 * @param {Mixed} date The date value
12052 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
12055 * @cfg {String} format
12056 * The default date format string which can be overriden for localization support. The format must be
12057 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
12061 * @cfg {String} altFormats
12062 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
12063 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
12065 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
12073 todayHighlight : false,
12079 keyboardNavigation: true,
12081 calendarWeeks: false,
12083 startDate: -Infinity,
12087 daysOfWeekDisabled: [],
12091 UTCDate: function()
12093 return new Date(Date.UTC.apply(Date, arguments));
12096 UTCToday: function()
12098 var today = new Date();
12099 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
12102 getDate: function() {
12103 var d = this.getUTCDate();
12104 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
12107 getUTCDate: function() {
12111 setDate: function(d) {
12112 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
12115 setUTCDate: function(d) {
12117 this.setValue(this.formatDate(this.date));
12120 onRender: function(ct, position)
12123 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
12125 this.language = this.language || 'en';
12126 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
12127 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
12129 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
12130 this.format = this.format || 'm/d/y';
12131 this.isInline = false;
12132 this.isInput = true;
12133 this.component = this.el.select('.add-on', true).first() || false;
12134 this.component = (this.component && this.component.length === 0) ? false : this.component;
12135 this.hasInput = this.component && this.inputEL().length;
12137 if (typeof(this.minViewMode === 'string')) {
12138 switch (this.minViewMode) {
12140 this.minViewMode = 1;
12143 this.minViewMode = 2;
12146 this.minViewMode = 0;
12151 if (typeof(this.viewMode === 'string')) {
12152 switch (this.viewMode) {
12165 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
12167 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12169 this.picker().on('mousedown', this.onMousedown, this);
12170 this.picker().on('click', this.onClick, this);
12172 this.picker().addClass('datepicker-dropdown');
12174 this.startViewMode = this.viewMode;
12177 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
12178 if(!this.calendarWeeks){
12183 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
12184 v.attr('colspan', function(i, val){
12185 return parseInt(val) + 1;
12190 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
12192 this.setStartDate(this.startDate);
12193 this.setEndDate(this.endDate);
12195 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
12202 if(this.isInline) {
12207 picker : function()
12209 return this.el.select('.datepicker', true).first();
12212 fillDow: function()
12214 var dowCnt = this.weekStart;
12223 if(this.calendarWeeks){
12231 while (dowCnt < this.weekStart + 7) {
12235 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
12239 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
12242 fillMonths: function()
12245 var months = this.picker().select('>.datepicker-months td', true).first();
12247 months.dom.innerHTML = '';
12253 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
12256 months.createChild(month);
12261 update: function(){
12263 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
12265 if (this.date < this.startDate) {
12266 this.viewDate = new Date(this.startDate);
12267 } else if (this.date > this.endDate) {
12268 this.viewDate = new Date(this.endDate);
12270 this.viewDate = new Date(this.date);
12277 var d = new Date(this.viewDate),
12278 year = d.getUTCFullYear(),
12279 month = d.getUTCMonth(),
12280 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
12281 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
12282 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
12283 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
12284 currentDate = this.date && this.date.valueOf(),
12285 today = this.UTCToday();
12287 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
12289 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
12291 // this.picker.select('>tfoot th.today').
12292 // .text(dates[this.language].today)
12293 // .toggle(this.todayBtn !== false);
12295 this.updateNavArrows();
12298 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
12300 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
12302 prevMonth.setUTCDate(day);
12304 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
12306 var nextMonth = new Date(prevMonth);
12308 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
12310 nextMonth = nextMonth.valueOf();
12312 var fillMonths = false;
12314 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
12316 while(prevMonth.valueOf() < nextMonth) {
12319 if (prevMonth.getUTCDay() === this.weekStart) {
12321 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
12329 if(this.calendarWeeks){
12330 // ISO 8601: First week contains first thursday.
12331 // ISO also states week starts on Monday, but we can be more abstract here.
12333 // Start of current week: based on weekstart/current date
12334 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
12335 // Thursday of this week
12336 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
12337 // First Thursday of year, year from thursday
12338 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
12339 // Calendar week: ms between thursdays, div ms per day, div 7 days
12340 calWeek = (th - yth) / 864e5 / 7 + 1;
12342 fillMonths.cn.push({
12350 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
12352 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
12355 if (this.todayHighlight &&
12356 prevMonth.getUTCFullYear() == today.getFullYear() &&
12357 prevMonth.getUTCMonth() == today.getMonth() &&
12358 prevMonth.getUTCDate() == today.getDate()) {
12359 clsName += ' today';
12362 if (currentDate && prevMonth.valueOf() === currentDate) {
12363 clsName += ' active';
12366 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
12367 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
12368 clsName += ' disabled';
12371 fillMonths.cn.push({
12373 cls: 'day ' + clsName,
12374 html: prevMonth.getDate()
12377 prevMonth.setDate(prevMonth.getDate()+1);
12380 var currentYear = this.date && this.date.getUTCFullYear();
12381 var currentMonth = this.date && this.date.getUTCMonth();
12383 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
12385 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
12386 v.removeClass('active');
12388 if(currentYear === year && k === currentMonth){
12389 v.addClass('active');
12392 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
12393 v.addClass('disabled');
12399 year = parseInt(year/10, 10) * 10;
12401 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
12403 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
12406 for (var i = -1; i < 11; i++) {
12407 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
12409 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
12417 showMode: function(dir) {
12419 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
12421 Roo.each(this.picker().select('>div',true).elements, function(v){
12422 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12425 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
12430 if(this.isInline) return;
12432 this.picker().removeClass(['bottom', 'top']);
12434 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
12436 * place to the top of element!
12440 this.picker().addClass('top');
12441 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12446 this.picker().addClass('bottom');
12448 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12451 parseDate : function(value){
12452 if(!value || value instanceof Date){
12455 var v = Date.parseDate(value, this.format);
12456 if (!v && this.useIso) {
12457 v = Date.parseDate(value, 'Y-m-d');
12459 if(!v && this.altFormats){
12460 if(!this.altFormatsArray){
12461 this.altFormatsArray = this.altFormats.split("|");
12463 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
12464 v = Date.parseDate(value, this.altFormatsArray[i]);
12470 formatDate : function(date, fmt){
12471 return (!date || !(date instanceof Date)) ?
12472 date : date.dateFormat(fmt || this.format);
12475 onFocus : function()
12477 Roo.bootstrap.DateField.superclass.onFocus.call(this);
12481 onBlur : function()
12483 Roo.bootstrap.DateField.superclass.onBlur.call(this);
12489 this.picker().show();
12493 this.fireEvent('show', this, this.date);
12498 if(this.isInline) return;
12499 this.picker().hide();
12500 this.viewMode = this.startViewMode;
12503 this.fireEvent('hide', this, this.date);
12507 onMousedown: function(e){
12508 e.stopPropagation();
12509 e.preventDefault();
12512 keyup: function(e){
12513 Roo.bootstrap.DateField.superclass.keyup.call(this);
12518 setValue: function(v){
12519 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
12521 this.fireEvent('select', this, this.date);
12525 fireKey: function(e){
12526 if (!this.picker().isVisible()){
12527 if (e.keyCode == 27) // allow escape to hide and re-show picker
12531 var dateChanged = false,
12533 newDate, newViewDate;
12537 e.preventDefault();
12541 if (!this.keyboardNavigation) break;
12542 dir = e.keyCode == 37 ? -1 : 1;
12545 newDate = this.moveYear(this.date, dir);
12546 newViewDate = this.moveYear(this.viewDate, dir);
12547 } else if (e.shiftKey){
12548 newDate = this.moveMonth(this.date, dir);
12549 newViewDate = this.moveMonth(this.viewDate, dir);
12551 newDate = new Date(this.date);
12552 newDate.setUTCDate(this.date.getUTCDate() + dir);
12553 newViewDate = new Date(this.viewDate);
12554 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
12556 if (this.dateWithinRange(newDate)){
12557 this.date = newDate;
12558 this.viewDate = newViewDate;
12559 this.setValue(this.formatDate(this.date));
12561 e.preventDefault();
12562 dateChanged = true;
12567 if (!this.keyboardNavigation) break;
12568 dir = e.keyCode == 38 ? -1 : 1;
12570 newDate = this.moveYear(this.date, dir);
12571 newViewDate = this.moveYear(this.viewDate, dir);
12572 } else if (e.shiftKey){
12573 newDate = this.moveMonth(this.date, dir);
12574 newViewDate = this.moveMonth(this.viewDate, dir);
12576 newDate = new Date(this.date);
12577 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
12578 newViewDate = new Date(this.viewDate);
12579 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
12581 if (this.dateWithinRange(newDate)){
12582 this.date = newDate;
12583 this.viewDate = newViewDate;
12584 this.setValue(this.formatDate(this.date));
12586 e.preventDefault();
12587 dateChanged = true;
12591 this.setValue(this.formatDate(this.date));
12593 e.preventDefault();
12596 this.setValue(this.formatDate(this.date));
12603 onClick: function(e) {
12604 e.stopPropagation();
12605 e.preventDefault();
12607 var target = e.getTarget();
12609 if(target.nodeName.toLowerCase() === 'i'){
12610 target = Roo.get(target).dom.parentNode;
12613 var nodeName = target.nodeName;
12614 var className = target.className;
12615 var html = target.innerHTML;
12617 switch(nodeName.toLowerCase()) {
12619 switch(className) {
12625 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
12626 switch(this.viewMode){
12628 this.viewDate = this.moveMonth(this.viewDate, dir);
12632 this.viewDate = this.moveYear(this.viewDate, dir);
12638 var date = new Date();
12639 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
12641 this.setValue(this.formatDate(this.date));
12647 if (className.indexOf('disabled') === -1) {
12648 this.viewDate.setUTCDate(1);
12649 if (className.indexOf('month') !== -1) {
12650 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
12652 var year = parseInt(html, 10) || 0;
12653 this.viewDate.setUTCFullYear(year);
12662 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
12663 var day = parseInt(html, 10) || 1;
12664 var year = this.viewDate.getUTCFullYear(),
12665 month = this.viewDate.getUTCMonth();
12667 if (className.indexOf('old') !== -1) {
12674 } else if (className.indexOf('new') !== -1) {
12682 this.date = this.UTCDate(year, month, day,0,0,0,0);
12683 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
12685 this.setValue(this.formatDate(this.date));
12692 setStartDate: function(startDate){
12693 this.startDate = startDate || -Infinity;
12694 if (this.startDate !== -Infinity) {
12695 this.startDate = this.parseDate(this.startDate);
12698 this.updateNavArrows();
12701 setEndDate: function(endDate){
12702 this.endDate = endDate || Infinity;
12703 if (this.endDate !== Infinity) {
12704 this.endDate = this.parseDate(this.endDate);
12707 this.updateNavArrows();
12710 setDaysOfWeekDisabled: function(daysOfWeekDisabled){
12711 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
12712 if (typeof(this.daysOfWeekDisabled) !== 'object') {
12713 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
12715 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
12716 return parseInt(d, 10);
12719 this.updateNavArrows();
12722 updateNavArrows: function() {
12723 var d = new Date(this.viewDate),
12724 year = d.getUTCFullYear(),
12725 month = d.getUTCMonth();
12727 Roo.each(this.picker().select('.prev', true).elements, function(v){
12729 switch (this.viewMode) {
12732 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
12738 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
12745 Roo.each(this.picker().select('.next', true).elements, function(v){
12747 switch (this.viewMode) {
12750 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
12756 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
12764 moveMonth: function(date, dir){
12765 if (!dir) return date;
12766 var new_date = new Date(date.valueOf()),
12767 day = new_date.getUTCDate(),
12768 month = new_date.getUTCMonth(),
12769 mag = Math.abs(dir),
12771 dir = dir > 0 ? 1 : -1;
12774 // If going back one month, make sure month is not current month
12775 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
12777 return new_date.getUTCMonth() == month;
12779 // If going forward one month, make sure month is as expected
12780 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
12782 return new_date.getUTCMonth() != new_month;
12784 new_month = month + dir;
12785 new_date.setUTCMonth(new_month);
12786 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
12787 if (new_month < 0 || new_month > 11)
12788 new_month = (new_month + 12) % 12;
12790 // For magnitudes >1, move one month at a time...
12791 for (var i=0; i<mag; i++)
12792 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
12793 new_date = this.moveMonth(new_date, dir);
12794 // ...then reset the day, keeping it in the new month
12795 new_month = new_date.getUTCMonth();
12796 new_date.setUTCDate(day);
12798 return new_month != new_date.getUTCMonth();
12801 // Common date-resetting loop -- if date is beyond end of month, make it
12804 new_date.setUTCDate(--day);
12805 new_date.setUTCMonth(new_month);
12810 moveYear: function(date, dir){
12811 return this.moveMonth(date, dir*12);
12814 dateWithinRange: function(date){
12815 return date >= this.startDate && date <= this.endDate;
12819 remove: function() {
12820 this.picker().remove();
12825 Roo.apply(Roo.bootstrap.DateField, {
12836 html: '<i class="icon-arrow-left"/>'
12846 html: '<i class="icon-arrow-right"/>'
12888 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
12889 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
12890 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
12891 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
12892 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
12905 navFnc: 'FullYear',
12910 navFnc: 'FullYear',
12915 Roo.apply(Roo.bootstrap.DateField, {
12919 cls: 'datepicker dropdown-menu',
12923 cls: 'datepicker-days',
12927 cls: 'table-condensed',
12929 Roo.bootstrap.DateField.head,
12933 Roo.bootstrap.DateField.footer
12940 cls: 'datepicker-months',
12944 cls: 'table-condensed',
12946 Roo.bootstrap.DateField.head,
12947 Roo.bootstrap.DateField.content,
12948 Roo.bootstrap.DateField.footer
12955 cls: 'datepicker-years',
12959 cls: 'table-condensed',
12961 Roo.bootstrap.DateField.head,
12962 Roo.bootstrap.DateField.content,
12963 Roo.bootstrap.DateField.footer
12982 * @class Roo.bootstrap.TimeField
12983 * @extends Roo.bootstrap.Input
12984 * Bootstrap DateField class
12988 * Create a new TimeField
12989 * @param {Object} config The config object
12992 Roo.bootstrap.TimeField = function(config){
12993 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
12997 * Fires when this field show.
12998 * @param {Roo.bootstrap.DateField} this
12999 * @param {Mixed} date The date value
13004 * Fires when this field hide.
13005 * @param {Roo.bootstrap.DateField} this
13006 * @param {Mixed} date The date value
13011 * Fires when select a date.
13012 * @param {Roo.bootstrap.DateField} this
13013 * @param {Mixed} date The date value
13019 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
13022 * @cfg {String} format
13023 * The default time format string which can be overriden for localization support. The format must be
13024 * valid according to {@link Date#parseDate} (defaults to 'H:i').
13028 onRender: function(ct, position)
13031 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
13033 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
13035 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13037 this.pop = this.picker().select('>.datepicker-time',true).first();
13038 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
13040 this.picker().on('mousedown', this.onMousedown, this);
13041 this.picker().on('click', this.onClick, this);
13043 this.picker().addClass('datepicker-dropdown');
13048 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
13049 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
13050 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
13051 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
13052 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
13053 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
13057 fireKey: function(e){
13058 if (!this.picker().isVisible()){
13059 if (e.keyCode == 27) // allow escape to hide and re-show picker
13064 e.preventDefault();
13072 this.onTogglePeriod();
13075 this.onIncrementMinutes();
13078 this.onDecrementMinutes();
13087 onClick: function(e) {
13088 e.stopPropagation();
13089 e.preventDefault();
13092 picker : function()
13094 return this.el.select('.datepicker', true).first();
13097 fillTime: function()
13099 var time = this.pop.select('tbody', true).first();
13101 time.dom.innerHTML = '';
13116 cls: 'hours-up glyphicon glyphicon-chevron-up'
13136 cls: 'minutes-up glyphicon glyphicon-chevron-up'
13157 cls: 'timepicker-hour',
13172 cls: 'timepicker-minute',
13187 cls: 'btn btn-primary period',
13209 cls: 'hours-down glyphicon glyphicon-chevron-down'
13229 cls: 'minutes-down glyphicon glyphicon-chevron-down'
13247 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
13254 var hours = this.time.getHours();
13255 var minutes = this.time.getMinutes();
13268 hours = hours - 12;
13272 hours = '0' + hours;
13276 minutes = '0' + minutes;
13279 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
13280 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
13281 this.pop.select('button', true).first().dom.innerHTML = period;
13287 this.picker().removeClass(['bottom', 'top']);
13289 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
13291 * place to the top of element!
13295 this.picker().addClass('top');
13296 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13301 this.picker().addClass('bottom');
13303 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13306 onFocus : function()
13308 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
13312 onBlur : function()
13314 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
13320 this.picker().show();
13325 this.fireEvent('show', this, this.date);
13330 this.picker().hide();
13333 this.fireEvent('hide', this, this.date);
13336 setTime : function()
13339 this.setValue(this.time.format(this.format));
13341 this.fireEvent('select', this, this.date);
13346 onMousedown: function(e){
13347 e.stopPropagation();
13348 e.preventDefault();
13351 onIncrementHours: function()
13353 Roo.log('onIncrementHours');
13354 this.time = this.time.add(Date.HOUR, 1);
13359 onDecrementHours: function()
13361 Roo.log('onDecrementHours');
13362 this.time = this.time.add(Date.HOUR, -1);
13366 onIncrementMinutes: function()
13368 Roo.log('onIncrementMinutes');
13369 this.time = this.time.add(Date.MINUTE, 1);
13373 onDecrementMinutes: function()
13375 Roo.log('onDecrementMinutes');
13376 this.time = this.time.add(Date.MINUTE, -1);
13380 onTogglePeriod: function()
13382 Roo.log('onTogglePeriod');
13383 this.time = this.time.add(Date.HOUR, 12);
13390 Roo.apply(Roo.bootstrap.TimeField, {
13420 cls: 'btn btn-info ok',
13432 Roo.apply(Roo.bootstrap.TimeField, {
13436 cls: 'datepicker dropdown-menu',
13440 cls: 'datepicker-time',
13444 cls: 'table-condensed',
13446 Roo.bootstrap.TimeField.content,
13447 Roo.bootstrap.TimeField.footer
13466 * @class Roo.bootstrap.CheckBox
13467 * @extends Roo.bootstrap.Input
13468 * Bootstrap CheckBox class
13470 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
13471 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
13472 * @cfg {String} boxLabel The text that appears beside the checkbox
13473 * @cfg {Boolean} checked initnal the element
13476 * Create a new CheckBox
13477 * @param {Object} config The config object
13480 Roo.bootstrap.CheckBox = function(config){
13481 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
13486 * Fires when the element is checked or unchecked.
13487 * @param {Roo.bootstrap.CheckBox} this This input
13488 * @param {Boolean} checked The new checked value
13494 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
13496 inputType: 'checkbox',
13502 getAutoCreate : function()
13504 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
13510 cfg.cls = 'form-group' //input-group
13515 type : this.inputType,
13516 value : (!this.checked) ? this.valueOff : this.inputValue,
13518 placeholder : this.placeholder || ''
13522 if (this.disabled) {
13523 input.disabled=true;
13527 input.checked = this.checked;
13531 input.name = this.name;
13535 input.cls += ' input-' + this.size;
13539 ['xs','sm','md','lg'].map(function(size){
13540 if (settings[size]) {
13541 cfg.cls += ' col-' + size + '-' + settings[size];
13545 var inputblock = input;
13547 if (this.before || this.after) {
13550 cls : 'input-group',
13554 inputblock.cn.push({
13556 cls : 'input-group-addon',
13560 inputblock.cn.push(input);
13562 inputblock.cn.push({
13564 cls : 'input-group-addon',
13571 if (align ==='left' && this.fieldLabel.length) {
13572 Roo.log("left and has label");
13578 cls : 'control-label col-md-' + this.labelWidth,
13579 html : this.fieldLabel
13583 cls : "col-md-" + (12 - this.labelWidth),
13590 } else if ( this.fieldLabel.length) {
13595 tag: this.boxLabel ? 'span' : 'label',
13597 cls: 'control-label box-input-label',
13598 //cls : 'input-group-addon',
13599 html : this.fieldLabel
13609 Roo.log(" no label && no align");
13624 html: this.boxLabel
13633 * return the real input element.
13635 inputEl: function ()
13637 return this.el.select('input.form-box',true).first();
13642 return this.el.select('label.control-label',true).first();
13645 initEvents : function()
13647 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
13649 this.inputEl().on('click', this.onClick, this);
13653 onClick : function()
13655 this.setChecked(!this.checked);
13658 setChecked : function(state,suppressEvent)
13660 this.checked = state;
13662 this.inputEl().dom.checked = state;
13664 if(suppressEvent !== true){
13665 this.fireEvent('check', this, state);
13668 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
13672 setValue : function(v,suppressEvent)
13674 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
13688 * @class Roo.bootstrap.Radio
13689 * @extends Roo.bootstrap.CheckBox
13690 * Bootstrap Radio class
13693 * Create a new Radio
13694 * @param {Object} config The config object
13697 Roo.bootstrap.Radio = function(config){
13698 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
13702 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
13704 inputType: 'radio',
13708 getAutoCreate : function()
13710 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
13716 cfg.cls = 'form-group' //input-group
13721 type : this.inputType,
13722 value : (!this.checked) ? this.valueOff : this.inputValue,
13724 placeholder : this.placeholder || ''
13728 if (this.disabled) {
13729 input.disabled=true;
13733 input.checked = this.checked;
13737 input.name = this.name;
13741 input.cls += ' input-' + this.size;
13745 ['xs','sm','md','lg'].map(function(size){
13746 if (settings[size]) {
13747 cfg.cls += ' col-' + size + '-' + settings[size];
13751 var inputblock = input;
13753 if (this.before || this.after) {
13756 cls : 'input-group',
13760 inputblock.cn.push({
13762 cls : 'input-group-addon',
13766 inputblock.cn.push(input);
13768 inputblock.cn.push({
13770 cls : 'input-group-addon',
13777 if (align ==='left' && this.fieldLabel.length) {
13778 Roo.log("left and has label");
13784 cls : 'control-label col-md-' + this.labelWidth,
13785 html : this.fieldLabel
13789 cls : "col-md-" + (12 - this.labelWidth),
13796 } else if ( this.fieldLabel.length) {
13803 cls: 'control-label box-input-label',
13804 //cls : 'input-group-addon',
13805 html : this.fieldLabel
13815 Roo.log(" no label && no align");
13830 html: this.boxLabel
13838 onClick : function()
13840 this.setChecked(true);
13843 setChecked : function(state,suppressEvent)
13846 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
13847 v.dom.checked = false;
13851 this.checked = state;
13852 this.inputEl().dom.checked = state;
13854 if(suppressEvent !== true){
13855 this.fireEvent('check', this, state);
13858 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
13862 getGroupValue : function()
13865 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
13866 if(v.dom.checked == true){
13867 value = v.dom.value;
13875 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
13876 * @return {Mixed} value The field value
13878 getValue : function(){
13879 return this.getGroupValue();
13885 //<script type="text/javascript">
13888 * Based Ext JS Library 1.1.1
13889 * Copyright(c) 2006-2007, Ext JS, LLC.
13895 * @class Roo.HtmlEditorCore
13896 * @extends Roo.Component
13897 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
13899 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
13902 Roo.HtmlEditorCore = function(config){
13905 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
13908 * @event initialize
13909 * Fires when the editor is fully initialized (including the iframe)
13910 * @param {Roo.HtmlEditorCore} this
13915 * Fires when the editor is first receives the focus. Any insertion must wait
13916 * until after this event.
13917 * @param {Roo.HtmlEditorCore} this
13921 * @event beforesync
13922 * Fires before the textarea is updated with content from the editor iframe. Return false
13923 * to cancel the sync.
13924 * @param {Roo.HtmlEditorCore} this
13925 * @param {String} html
13929 * @event beforepush
13930 * Fires before the iframe editor is updated with content from the textarea. Return false
13931 * to cancel the push.
13932 * @param {Roo.HtmlEditorCore} this
13933 * @param {String} html
13938 * Fires when the textarea is updated with content from the editor iframe.
13939 * @param {Roo.HtmlEditorCore} this
13940 * @param {String} html
13945 * Fires when the iframe editor is updated with content from the textarea.
13946 * @param {Roo.HtmlEditorCore} this
13947 * @param {String} html
13952 * @event editorevent
13953 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
13954 * @param {Roo.HtmlEditorCore} this
13962 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
13966 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
13972 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
13977 * @cfg {Number} height (in pixels)
13981 * @cfg {Number} width (in pixels)
13986 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
13989 stylesheets: false,
13994 // private properties
13995 validationEvent : false,
13997 initialized : false,
13999 sourceEditMode : false,
14000 onFocus : Roo.emptyFn,
14002 hideMode:'offsets',
14010 * Protected method that will not generally be called directly. It
14011 * is called when the editor initializes the iframe with HTML contents. Override this method if you
14012 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
14014 getDocMarkup : function(){
14017 Roo.log(this.stylesheets);
14019 // inherit styels from page...??
14020 if (this.stylesheets === false) {
14022 Roo.get(document.head).select('style').each(function(node) {
14023 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
14026 Roo.get(document.head).select('link').each(function(node) {
14027 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
14030 } else if (!this.stylesheets.length) {
14032 st = '<style type="text/css">' +
14033 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
14036 Roo.each(this.stylesheets, function(s) {
14037 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
14042 st += '<style type="text/css">' +
14043 'IMG { cursor: pointer } ' +
14047 return '<html><head>' + st +
14048 //<style type="text/css">' +
14049 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
14051 ' </head><body class="roo-htmleditor-body"></body></html>';
14055 onRender : function(ct, position)
14058 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
14059 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
14062 this.el.dom.style.border = '0 none';
14063 this.el.dom.setAttribute('tabIndex', -1);
14064 this.el.addClass('x-hidden hide');
14068 if(Roo.isIE){ // fix IE 1px bogus margin
14069 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
14073 this.frameId = Roo.id();
14077 var iframe = this.owner.wrap.createChild({
14079 cls: 'form-control', // bootstrap..
14081 name: this.frameId,
14082 frameBorder : 'no',
14083 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
14088 this.iframe = iframe.dom;
14090 this.assignDocWin();
14092 this.doc.designMode = 'on';
14095 this.doc.write(this.getDocMarkup());
14099 var task = { // must defer to wait for browser to be ready
14101 //console.log("run task?" + this.doc.readyState);
14102 this.assignDocWin();
14103 if(this.doc.body || this.doc.readyState == 'complete'){
14105 this.doc.designMode="on";
14109 Roo.TaskMgr.stop(task);
14110 this.initEditor.defer(10, this);
14117 Roo.TaskMgr.start(task);
14124 onResize : function(w, h)
14126 Roo.log('resize: ' +w + ',' + h );
14127 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
14131 if(typeof w == 'number'){
14133 this.iframe.style.width = w + 'px';
14135 if(typeof h == 'number'){
14137 this.iframe.style.height = h + 'px';
14139 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
14146 * Toggles the editor between standard and source edit mode.
14147 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
14149 toggleSourceEdit : function(sourceEditMode){
14151 this.sourceEditMode = sourceEditMode === true;
14153 if(this.sourceEditMode){
14155 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
14158 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
14159 //this.iframe.className = '';
14162 //this.setSize(this.owner.wrap.getSize());
14163 //this.fireEvent('editmodechange', this, this.sourceEditMode);
14170 * Protected method that will not generally be called directly. If you need/want
14171 * custom HTML cleanup, this is the method you should override.
14172 * @param {String} html The HTML to be cleaned
14173 * return {String} The cleaned HTML
14175 cleanHtml : function(html){
14176 html = String(html);
14177 if(html.length > 5){
14178 if(Roo.isSafari){ // strip safari nonsense
14179 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
14182 if(html == ' '){
14189 * HTML Editor -> Textarea
14190 * Protected method that will not generally be called directly. Syncs the contents
14191 * of the editor iframe with the textarea.
14193 syncValue : function(){
14194 if(this.initialized){
14195 var bd = (this.doc.body || this.doc.documentElement);
14196 //this.cleanUpPaste(); -- this is done else where and causes havoc..
14197 var html = bd.innerHTML;
14199 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
14200 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
14202 html = '<div style="'+m[0]+'">' + html + '</div>';
14205 html = this.cleanHtml(html);
14206 // fix up the special chars.. normaly like back quotes in word...
14207 // however we do not want to do this with chinese..
14208 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
14209 var cc = b.charCodeAt();
14211 (cc >= 0x4E00 && cc < 0xA000 ) ||
14212 (cc >= 0x3400 && cc < 0x4E00 ) ||
14213 (cc >= 0xf900 && cc < 0xfb00 )
14219 if(this.owner.fireEvent('beforesync', this, html) !== false){
14220 this.el.dom.value = html;
14221 this.owner.fireEvent('sync', this, html);
14227 * Protected method that will not generally be called directly. Pushes the value of the textarea
14228 * into the iframe editor.
14230 pushValue : function(){
14231 if(this.initialized){
14232 var v = this.el.dom.value.trim();
14234 // if(v.length < 1){
14238 if(this.owner.fireEvent('beforepush', this, v) !== false){
14239 var d = (this.doc.body || this.doc.documentElement);
14241 this.cleanUpPaste();
14242 this.el.dom.value = d.innerHTML;
14243 this.owner.fireEvent('push', this, v);
14249 deferFocus : function(){
14250 this.focus.defer(10, this);
14254 focus : function(){
14255 if(this.win && !this.sourceEditMode){
14262 assignDocWin: function()
14264 var iframe = this.iframe;
14267 this.doc = iframe.contentWindow.document;
14268 this.win = iframe.contentWindow;
14270 if (!Roo.get(this.frameId)) {
14273 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
14274 this.win = Roo.get(this.frameId).dom.contentWindow;
14279 initEditor : function(){
14280 //console.log("INIT EDITOR");
14281 this.assignDocWin();
14285 this.doc.designMode="on";
14287 this.doc.write(this.getDocMarkup());
14290 var dbody = (this.doc.body || this.doc.documentElement);
14291 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
14292 // this copies styles from the containing element into thsi one..
14293 // not sure why we need all of this..
14294 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
14295 ss['background-attachment'] = 'fixed'; // w3c
14296 dbody.bgProperties = 'fixed'; // ie
14297 Roo.DomHelper.applyStyles(dbody, ss);
14298 Roo.EventManager.on(this.doc, {
14299 //'mousedown': this.onEditorEvent,
14300 'mouseup': this.onEditorEvent,
14301 'dblclick': this.onEditorEvent,
14302 'click': this.onEditorEvent,
14303 'keyup': this.onEditorEvent,
14308 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
14310 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
14311 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
14313 this.initialized = true;
14315 this.owner.fireEvent('initialize', this);
14320 onDestroy : function(){
14326 //for (var i =0; i < this.toolbars.length;i++) {
14327 // // fixme - ask toolbars for heights?
14328 // this.toolbars[i].onDestroy();
14331 //this.wrap.dom.innerHTML = '';
14332 //this.wrap.remove();
14337 onFirstFocus : function(){
14339 this.assignDocWin();
14342 this.activated = true;
14345 if(Roo.isGecko){ // prevent silly gecko errors
14347 var s = this.win.getSelection();
14348 if(!s.focusNode || s.focusNode.nodeType != 3){
14349 var r = s.getRangeAt(0);
14350 r.selectNodeContents((this.doc.body || this.doc.documentElement));
14355 this.execCmd('useCSS', true);
14356 this.execCmd('styleWithCSS', false);
14359 this.owner.fireEvent('activate', this);
14363 adjustFont: function(btn){
14364 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
14365 //if(Roo.isSafari){ // safari
14368 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
14369 if(Roo.isSafari){ // safari
14370 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
14371 v = (v < 10) ? 10 : v;
14372 v = (v > 48) ? 48 : v;
14373 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
14378 v = Math.max(1, v+adjust);
14380 this.execCmd('FontSize', v );
14383 onEditorEvent : function(e){
14384 this.owner.fireEvent('editorevent', this, e);
14385 // this.updateToolbar();
14386 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
14389 insertTag : function(tg)
14391 // could be a bit smarter... -> wrap the current selected tRoo..
14392 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
14394 range = this.createRange(this.getSelection());
14395 var wrappingNode = this.doc.createElement(tg.toLowerCase());
14396 wrappingNode.appendChild(range.extractContents());
14397 range.insertNode(wrappingNode);
14404 this.execCmd("formatblock", tg);
14408 insertText : function(txt)
14412 var range = this.createRange();
14413 range.deleteContents();
14414 //alert(Sender.getAttribute('label'));
14416 range.insertNode(this.doc.createTextNode(txt));
14422 * Executes a Midas editor command on the editor document and performs necessary focus and
14423 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
14424 * @param {String} cmd The Midas command
14425 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
14427 relayCmd : function(cmd, value){
14429 this.execCmd(cmd, value);
14430 this.owner.fireEvent('editorevent', this);
14431 //this.updateToolbar();
14432 this.owner.deferFocus();
14436 * Executes a Midas editor command directly on the editor document.
14437 * For visual commands, you should use {@link #relayCmd} instead.
14438 * <b>This should only be called after the editor is initialized.</b>
14439 * @param {String} cmd The Midas command
14440 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
14442 execCmd : function(cmd, value){
14443 this.doc.execCommand(cmd, false, value === undefined ? null : value);
14450 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
14452 * @param {String} text | dom node..
14454 insertAtCursor : function(text)
14459 if(!this.activated){
14465 var r = this.doc.selection.createRange();
14476 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
14480 // from jquery ui (MIT licenced)
14482 var win = this.win;
14484 if (win.getSelection && win.getSelection().getRangeAt) {
14485 range = win.getSelection().getRangeAt(0);
14486 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
14487 range.insertNode(node);
14488 } else if (win.document.selection && win.document.selection.createRange) {
14489 // no firefox support
14490 var txt = typeof(text) == 'string' ? text : text.outerHTML;
14491 win.document.selection.createRange().pasteHTML(txt);
14493 // no firefox support
14494 var txt = typeof(text) == 'string' ? text : text.outerHTML;
14495 this.execCmd('InsertHTML', txt);
14504 mozKeyPress : function(e){
14506 var c = e.getCharCode(), cmd;
14509 c = String.fromCharCode(c).toLowerCase();
14523 this.cleanUpPaste.defer(100, this);
14531 e.preventDefault();
14539 fixKeys : function(){ // load time branching for fastest keydown performance
14541 return function(e){
14542 var k = e.getKey(), r;
14545 r = this.doc.selection.createRange();
14548 r.pasteHTML('    ');
14555 r = this.doc.selection.createRange();
14557 var target = r.parentElement();
14558 if(!target || target.tagName.toLowerCase() != 'li'){
14560 r.pasteHTML('<br />');
14566 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
14567 this.cleanUpPaste.defer(100, this);
14573 }else if(Roo.isOpera){
14574 return function(e){
14575 var k = e.getKey();
14579 this.execCmd('InsertHTML','    ');
14582 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
14583 this.cleanUpPaste.defer(100, this);
14588 }else if(Roo.isSafari){
14589 return function(e){
14590 var k = e.getKey();
14594 this.execCmd('InsertText','\t');
14598 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
14599 this.cleanUpPaste.defer(100, this);
14607 getAllAncestors: function()
14609 var p = this.getSelectedNode();
14612 a.push(p); // push blank onto stack..
14613 p = this.getParentElement();
14617 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
14621 a.push(this.doc.body);
14625 lastSelNode : false,
14628 getSelection : function()
14630 this.assignDocWin();
14631 return Roo.isIE ? this.doc.selection : this.win.getSelection();
14634 getSelectedNode: function()
14636 // this may only work on Gecko!!!
14638 // should we cache this!!!!
14643 var range = this.createRange(this.getSelection()).cloneRange();
14646 var parent = range.parentElement();
14648 var testRange = range.duplicate();
14649 testRange.moveToElementText(parent);
14650 if (testRange.inRange(range)) {
14653 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
14656 parent = parent.parentElement;
14661 // is ancestor a text element.
14662 var ac = range.commonAncestorContainer;
14663 if (ac.nodeType == 3) {
14664 ac = ac.parentNode;
14667 var ar = ac.childNodes;
14670 var other_nodes = [];
14671 var has_other_nodes = false;
14672 for (var i=0;i<ar.length;i++) {
14673 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
14676 // fullly contained node.
14678 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
14683 // probably selected..
14684 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
14685 other_nodes.push(ar[i]);
14689 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
14694 has_other_nodes = true;
14696 if (!nodes.length && other_nodes.length) {
14697 nodes= other_nodes;
14699 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
14705 createRange: function(sel)
14707 // this has strange effects when using with
14708 // top toolbar - not sure if it's a great idea.
14709 //this.editor.contentWindow.focus();
14710 if (typeof sel != "undefined") {
14712 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
14714 return this.doc.createRange();
14717 return this.doc.createRange();
14720 getParentElement: function()
14723 this.assignDocWin();
14724 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
14726 var range = this.createRange(sel);
14729 var p = range.commonAncestorContainer;
14730 while (p.nodeType == 3) { // text node
14741 * Range intersection.. the hard stuff...
14745 * [ -- selected range --- ]
14749 * if end is before start or hits it. fail.
14750 * if start is after end or hits it fail.
14752 * if either hits (but other is outside. - then it's not
14758 // @see http://www.thismuchiknow.co.uk/?p=64.
14759 rangeIntersectsNode : function(range, node)
14761 var nodeRange = node.ownerDocument.createRange();
14763 nodeRange.selectNode(node);
14765 nodeRange.selectNodeContents(node);
14768 var rangeStartRange = range.cloneRange();
14769 rangeStartRange.collapse(true);
14771 var rangeEndRange = range.cloneRange();
14772 rangeEndRange.collapse(false);
14774 var nodeStartRange = nodeRange.cloneRange();
14775 nodeStartRange.collapse(true);
14777 var nodeEndRange = nodeRange.cloneRange();
14778 nodeEndRange.collapse(false);
14780 return rangeStartRange.compareBoundaryPoints(
14781 Range.START_TO_START, nodeEndRange) == -1 &&
14782 rangeEndRange.compareBoundaryPoints(
14783 Range.START_TO_START, nodeStartRange) == 1;
14787 rangeCompareNode : function(range, node)
14789 var nodeRange = node.ownerDocument.createRange();
14791 nodeRange.selectNode(node);
14793 nodeRange.selectNodeContents(node);
14797 range.collapse(true);
14799 nodeRange.collapse(true);
14801 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
14802 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
14804 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
14806 var nodeIsBefore = ss == 1;
14807 var nodeIsAfter = ee == -1;
14809 if (nodeIsBefore && nodeIsAfter)
14811 if (!nodeIsBefore && nodeIsAfter)
14812 return 1; //right trailed.
14814 if (nodeIsBefore && !nodeIsAfter)
14815 return 2; // left trailed.
14820 // private? - in a new class?
14821 cleanUpPaste : function()
14823 // cleans up the whole document..
14824 Roo.log('cleanuppaste');
14826 this.cleanUpChildren(this.doc.body);
14827 var clean = this.cleanWordChars(this.doc.body.innerHTML);
14828 if (clean != this.doc.body.innerHTML) {
14829 this.doc.body.innerHTML = clean;
14834 cleanWordChars : function(input) {// change the chars to hex code
14835 var he = Roo.HtmlEditorCore;
14837 var output = input;
14838 Roo.each(he.swapCodes, function(sw) {
14839 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
14841 output = output.replace(swapper, sw[1]);
14848 cleanUpChildren : function (n)
14850 if (!n.childNodes.length) {
14853 for (var i = n.childNodes.length-1; i > -1 ; i--) {
14854 this.cleanUpChild(n.childNodes[i]);
14861 cleanUpChild : function (node)
14864 //console.log(node);
14865 if (node.nodeName == "#text") {
14866 // clean up silly Windows -- stuff?
14869 if (node.nodeName == "#comment") {
14870 node.parentNode.removeChild(node);
14871 // clean up silly Windows -- stuff?
14875 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
14877 node.parentNode.removeChild(node);
14882 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
14884 // remove <a name=....> as rendering on yahoo mailer is borked with this.
14885 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
14887 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
14888 // remove_keep_children = true;
14891 if (remove_keep_children) {
14892 this.cleanUpChildren(node);
14893 // inserts everything just before this node...
14894 while (node.childNodes.length) {
14895 var cn = node.childNodes[0];
14896 node.removeChild(cn);
14897 node.parentNode.insertBefore(cn, node);
14899 node.parentNode.removeChild(node);
14903 if (!node.attributes || !node.attributes.length) {
14904 this.cleanUpChildren(node);
14908 function cleanAttr(n,v)
14911 if (v.match(/^\./) || v.match(/^\//)) {
14914 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
14917 if (v.match(/^#/)) {
14920 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
14921 node.removeAttribute(n);
14925 function cleanStyle(n,v)
14927 if (v.match(/expression/)) { //XSS?? should we even bother..
14928 node.removeAttribute(n);
14931 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
14932 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
14935 var parts = v.split(/;/);
14938 Roo.each(parts, function(p) {
14939 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
14943 var l = p.split(':').shift().replace(/\s+/g,'');
14944 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
14946 if ( cblack.indexOf(l) > -1) {
14947 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
14948 //node.removeAttribute(n);
14952 // only allow 'c whitelisted system attributes'
14953 if ( cwhite.length && cwhite.indexOf(l) < 0) {
14954 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
14955 //node.removeAttribute(n);
14965 if (clean.length) {
14966 node.setAttribute(n, clean.join(';'));
14968 node.removeAttribute(n);
14974 for (var i = node.attributes.length-1; i > -1 ; i--) {
14975 var a = node.attributes[i];
14978 if (a.name.toLowerCase().substr(0,2)=='on') {
14979 node.removeAttribute(a.name);
14982 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
14983 node.removeAttribute(a.name);
14986 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
14987 cleanAttr(a.name,a.value); // fixme..
14990 if (a.name == 'style') {
14991 cleanStyle(a.name,a.value);
14994 /// clean up MS crap..
14995 // tecnically this should be a list of valid class'es..
14998 if (a.name == 'class') {
14999 if (a.value.match(/^Mso/)) {
15000 node.className = '';
15003 if (a.value.match(/body/)) {
15004 node.className = '';
15015 this.cleanUpChildren(node);
15021 // hide stuff that is not compatible
15035 * @event specialkey
15039 * @cfg {String} fieldClass @hide
15042 * @cfg {String} focusClass @hide
15045 * @cfg {String} autoCreate @hide
15048 * @cfg {String} inputType @hide
15051 * @cfg {String} invalidClass @hide
15054 * @cfg {String} invalidText @hide
15057 * @cfg {String} msgFx @hide
15060 * @cfg {String} validateOnBlur @hide
15064 Roo.HtmlEditorCore.white = [
15065 'area', 'br', 'img', 'input', 'hr', 'wbr',
15067 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
15068 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
15069 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
15070 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
15071 'table', 'ul', 'xmp',
15073 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
15076 'dir', 'menu', 'ol', 'ul', 'dl',
15082 Roo.HtmlEditorCore.black = [
15083 // 'embed', 'object', // enable - backend responsiblity to clean thiese
15085 'base', 'basefont', 'bgsound', 'blink', 'body',
15086 'frame', 'frameset', 'head', 'html', 'ilayer',
15087 'iframe', 'layer', 'link', 'meta', 'object',
15088 'script', 'style' ,'title', 'xml' // clean later..
15090 Roo.HtmlEditorCore.clean = [
15091 'script', 'style', 'title', 'xml'
15093 Roo.HtmlEditorCore.remove = [
15098 Roo.HtmlEditorCore.ablack = [
15102 Roo.HtmlEditorCore.aclean = [
15103 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
15107 Roo.HtmlEditorCore.pwhite= [
15108 'http', 'https', 'mailto'
15111 // white listed style attributes.
15112 Roo.HtmlEditorCore.cwhite= [
15113 // 'text-align', /// default is to allow most things..
15119 // black listed style attributes.
15120 Roo.HtmlEditorCore.cblack= [
15121 // 'font-size' -- this can be set by the project
15125 Roo.HtmlEditorCore.swapCodes =[
15144 * @class Roo.bootstrap.HtmlEditor
15145 * @extends Roo.bootstrap.TextArea
15146 * Bootstrap HtmlEditor class
15149 * Create a new HtmlEditor
15150 * @param {Object} config The config object
15153 Roo.bootstrap.HtmlEditor = function(config){
15154 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
15155 if (!this.toolbars) {
15156 this.toolbars = [];
15158 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
15161 * @event initialize
15162 * Fires when the editor is fully initialized (including the iframe)
15163 * @param {HtmlEditor} this
15168 * Fires when the editor is first receives the focus. Any insertion must wait
15169 * until after this event.
15170 * @param {HtmlEditor} this
15174 * @event beforesync
15175 * Fires before the textarea is updated with content from the editor iframe. Return false
15176 * to cancel the sync.
15177 * @param {HtmlEditor} this
15178 * @param {String} html
15182 * @event beforepush
15183 * Fires before the iframe editor is updated with content from the textarea. Return false
15184 * to cancel the push.
15185 * @param {HtmlEditor} this
15186 * @param {String} html
15191 * Fires when the textarea is updated with content from the editor iframe.
15192 * @param {HtmlEditor} this
15193 * @param {String} html
15198 * Fires when the iframe editor is updated with content from the textarea.
15199 * @param {HtmlEditor} this
15200 * @param {String} html
15204 * @event editmodechange
15205 * Fires when the editor switches edit modes
15206 * @param {HtmlEditor} this
15207 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
15209 editmodechange: true,
15211 * @event editorevent
15212 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
15213 * @param {HtmlEditor} this
15217 * @event firstfocus
15218 * Fires when on first focus - needed by toolbars..
15219 * @param {HtmlEditor} this
15224 * Auto save the htmlEditor value as a file into Events
15225 * @param {HtmlEditor} this
15229 * @event savedpreview
15230 * preview the saved version of htmlEditor
15231 * @param {HtmlEditor} this
15238 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
15242 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
15247 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
15252 * @cfg {Number} height (in pixels)
15256 * @cfg {Number} width (in pixels)
15261 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
15264 stylesheets: false,
15269 // private properties
15270 validationEvent : false,
15272 initialized : false,
15275 onFocus : Roo.emptyFn,
15277 hideMode:'offsets',
15280 tbContainer : false,
15282 toolbarContainer :function() {
15283 return this.wrap.select('.x-html-editor-tb',true).first();
15287 * Protected method that will not generally be called directly. It
15288 * is called when the editor creates its toolbar. Override this method if you need to
15289 * add custom toolbar buttons.
15290 * @param {HtmlEditor} editor
15292 createToolbar : function(){
15294 Roo.log("create toolbars");
15296 this.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard({editor: this} ) ];
15297 this.toolbars[0].render(this.toolbarContainer());
15301 // if (!editor.toolbars || !editor.toolbars.length) {
15302 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
15305 // for (var i =0 ; i < editor.toolbars.length;i++) {
15306 // editor.toolbars[i] = Roo.factory(
15307 // typeof(editor.toolbars[i]) == 'string' ?
15308 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
15309 // Roo.bootstrap.HtmlEditor);
15310 // editor.toolbars[i].init(editor);
15316 onRender : function(ct, position)
15318 // Roo.log("Call onRender: " + this.xtype);
15320 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
15322 this.wrap = this.inputEl().wrap({
15323 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
15326 this.editorcore.onRender(ct, position);
15328 if (this.resizable) {
15329 this.resizeEl = new Roo.Resizable(this.wrap, {
15333 minHeight : this.height,
15334 height: this.height,
15335 handles : this.resizable,
15338 resize : function(r, w, h) {
15339 _t.onResize(w,h); // -something
15345 this.createToolbar(this);
15348 if(!this.width && this.resizable){
15349 this.setSize(this.wrap.getSize());
15351 if (this.resizeEl) {
15352 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
15353 // should trigger onReize..
15359 onResize : function(w, h)
15361 Roo.log('resize: ' +w + ',' + h );
15362 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
15366 if(this.inputEl() ){
15367 if(typeof w == 'number'){
15368 var aw = w - this.wrap.getFrameWidth('lr');
15369 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
15372 if(typeof h == 'number'){
15373 var tbh = -11; // fixme it needs to tool bar size!
15374 for (var i =0; i < this.toolbars.length;i++) {
15375 // fixme - ask toolbars for heights?
15376 tbh += this.toolbars[i].el.getHeight();
15377 //if (this.toolbars[i].footer) {
15378 // tbh += this.toolbars[i].footer.el.getHeight();
15386 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
15387 ah -= 5; // knock a few pixes off for look..
15388 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
15392 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
15393 this.editorcore.onResize(ew,eh);
15398 * Toggles the editor between standard and source edit mode.
15399 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
15401 toggleSourceEdit : function(sourceEditMode)
15403 this.editorcore.toggleSourceEdit(sourceEditMode);
15405 if(this.editorcore.sourceEditMode){
15406 Roo.log('editor - showing textarea');
15409 // Roo.log(this.syncValue());
15411 this.inputEl().removeClass('hide');
15412 this.inputEl().dom.removeAttribute('tabIndex');
15413 this.inputEl().focus();
15415 Roo.log('editor - hiding textarea');
15417 // Roo.log(this.pushValue());
15420 this.inputEl().addClass('hide');
15421 this.inputEl().dom.setAttribute('tabIndex', -1);
15422 //this.deferFocus();
15425 if(this.resizable){
15426 this.setSize(this.wrap.getSize());
15429 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
15432 // private (for BoxComponent)
15433 adjustSize : Roo.BoxComponent.prototype.adjustSize,
15435 // private (for BoxComponent)
15436 getResizeEl : function(){
15440 // private (for BoxComponent)
15441 getPositionEl : function(){
15446 initEvents : function(){
15447 this.originalValue = this.getValue();
15451 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
15454 // markInvalid : Roo.emptyFn,
15456 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
15459 // clearInvalid : Roo.emptyFn,
15461 setValue : function(v){
15462 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
15463 this.editorcore.pushValue();
15468 deferFocus : function(){
15469 this.focus.defer(10, this);
15473 focus : function(){
15474 this.editorcore.focus();
15480 onDestroy : function(){
15486 for (var i =0; i < this.toolbars.length;i++) {
15487 // fixme - ask toolbars for heights?
15488 this.toolbars[i].onDestroy();
15491 this.wrap.dom.innerHTML = '';
15492 this.wrap.remove();
15497 onFirstFocus : function(){
15498 //Roo.log("onFirstFocus");
15499 this.editorcore.onFirstFocus();
15500 for (var i =0; i < this.toolbars.length;i++) {
15501 this.toolbars[i].onFirstFocus();
15507 syncValue : function()
15509 this.editorcore.syncValue();
15512 pushValue : function()
15514 this.editorcore.pushValue();
15518 // hide stuff that is not compatible
15532 * @event specialkey
15536 * @cfg {String} fieldClass @hide
15539 * @cfg {String} focusClass @hide
15542 * @cfg {String} autoCreate @hide
15545 * @cfg {String} inputType @hide
15548 * @cfg {String} invalidClass @hide
15551 * @cfg {String} invalidText @hide
15554 * @cfg {String} msgFx @hide
15557 * @cfg {String} validateOnBlur @hide
15568 * @class Roo.bootstrap.HtmlEditorToolbar1
15573 new Roo.bootstrap.HtmlEditor({
15576 new Roo.bootstrap.HtmlEditorToolbar1({
15577 disable : { fonts: 1 , format: 1, ..., ... , ...],
15583 * @cfg {Object} disable List of elements to disable..
15584 * @cfg {Array} btns List of additional buttons.
15588 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
15591 Roo.bootstrap.HtmlEditor.ToolbarStandard = function(config)
15594 Roo.apply(this, config);
15596 // default disabled, based on 'good practice'..
15597 this.disable = this.disable || {};
15598 Roo.applyIf(this.disable, {
15601 specialElements : true
15603 Roo.bootstrap.HtmlEditor.ToolbarStandard.superclass.constructor.call(this, config);
15605 this.editor = config.editor;
15606 this.editorcore = config.editor.editorcore;
15608 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
15610 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
15611 // dont call parent... till later.
15613 Roo.extend(Roo.bootstrap.HtmlEditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
15619 editorcore : false,
15624 "h1","h2","h3","h4","h5","h6",
15626 "abbr", "acronym", "address", "cite", "samp", "var",
15630 onRender : function(ct, position)
15632 // Roo.log("Call onRender: " + this.xtype);
15634 Roo.bootstrap.HtmlEditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
15636 this.el.dom.style.marginBottom = '0';
15638 var editorcore = this.editorcore;
15639 var editor= this.editor;
15642 var btn = function(id,cmd , toggle, handler){
15644 var event = toggle ? 'toggle' : 'click';
15649 xns: Roo.bootstrap,
15652 enableToggle:toggle !== false,
15654 pressed : toggle ? false : null,
15657 a.listeners[toggle ? 'toggle' : 'click'] = function() {
15658 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
15667 xns: Roo.bootstrap,
15668 glyphicon : 'font',
15672 xns: Roo.bootstrap,
15676 Roo.each(this.formats, function(f) {
15677 style.menu.items.push({
15679 xns: Roo.bootstrap,
15680 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
15685 editorcore.insertTag(this.tagname);
15692 children.push(style);
15695 btn('bold',false,true);
15696 btn('italic',false,true);
15697 btn('align-left', 'justifyleft',true);
15698 btn('align-center', 'justifycenter',true);
15699 btn('align-right' , 'justifyright',true);
15700 btn('link', false, false, function(btn) {
15701 //Roo.log("create link?");
15702 var url = prompt(this.createLinkText, this.defaultLinkValue);
15703 if(url && url != 'http:/'+'/'){
15704 this.editorcore.relayCmd('createlink', url);
15707 btn('list','insertunorderedlist',true);
15708 btn('pencil', false,true, function(btn){
15711 this.toggleSourceEdit(btn.pressed);
15717 xns: Roo.bootstrap,
15722 xns: Roo.bootstrap,
15727 cog.menu.items.push({
15729 xns: Roo.bootstrap,
15730 html : Clean styles,
15735 editorcore.insertTag(this.tagname);
15744 this.xtype = 'NavSimplebar';
15746 for(var i=0;i< children.length;i++) {
15748 this.buttons.add(this.addxtypeChild(children[i]));
15752 editor.on('editorevent', this.updateToolbar, this);
15754 onBtnClick : function(id)
15756 this.editorcore.relayCmd(id);
15757 this.editorcore.focus();
15761 * Protected method that will not generally be called directly. It triggers
15762 * a toolbar update by reading the markup state of the current selection in the editor.
15764 updateToolbar: function(){
15766 if(!this.editorcore.activated){
15767 this.editor.onFirstFocus(); // is this neeed?
15771 var btns = this.buttons;
15772 var doc = this.editorcore.doc;
15773 btns.get('bold').setActive(doc.queryCommandState('bold'));
15774 btns.get('italic').setActive(doc.queryCommandState('italic'));
15775 //btns.get('underline').setActive(doc.queryCommandState('underline'));
15777 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
15778 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
15779 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
15781 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
15782 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
15785 var ans = this.editorcore.getAllAncestors();
15786 if (this.formatCombo) {
15789 var store = this.formatCombo.store;
15790 this.formatCombo.setValue("");
15791 for (var i =0; i < ans.length;i++) {
15792 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
15794 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
15802 // hides menus... - so this cant be on a menu...
15803 Roo.bootstrap.MenuMgr.hideAll();
15805 Roo.bootstrap.MenuMgr.hideAll();
15806 //this.editorsyncValue();
15808 onFirstFocus: function() {
15809 this.buttons.each(function(item){
15813 toggleSourceEdit : function(sourceEditMode){
15816 if(sourceEditMode){
15817 Roo.log("disabling buttons");
15818 this.buttons.each( function(item){
15819 if(item.cmd != 'pencil'){
15825 Roo.log("enabling buttons");
15826 if(this.editorcore.initialized){
15827 this.buttons.each( function(item){
15833 Roo.log("calling toggole on editor");
15834 // tell the editor that it's been pressed..
15835 this.editor.toggleSourceEdit(sourceEditMode);
15845 * @class Roo.bootstrap.Table.AbstractSelectionModel
15846 * @extends Roo.util.Observable
15847 * Abstract base class for grid SelectionModels. It provides the interface that should be
15848 * implemented by descendant classes. This class should not be directly instantiated.
15851 Roo.bootstrap.Table.AbstractSelectionModel = function(){
15852 this.locked = false;
15853 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
15857 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
15858 /** @ignore Called by the grid automatically. Do not call directly. */
15859 init : function(grid){
15865 * Locks the selections.
15868 this.locked = true;
15872 * Unlocks the selections.
15874 unlock : function(){
15875 this.locked = false;
15879 * Returns true if the selections are locked.
15880 * @return {Boolean}
15882 isLocked : function(){
15883 return this.locked;
15887 * @class Roo.bootstrap.Table.ColumnModel
15888 * @extends Roo.util.Observable
15889 * This is the default implementation of a ColumnModel used by the bootstrap table. It defines
15890 * the columns in the table.
15893 * @param {Object} config An Array of column config objects. See this class's
15894 * config objects for details.
15896 Roo.bootstrap.Table.ColumnModel = function(config){
15898 * The config passed into the constructor
15900 this.config = config;
15903 // if no id, create one
15904 // if the column does not have a dataIndex mapping,
15905 // map it to the order it is in the config
15906 for(var i = 0, len = config.length; i < len; i++){
15908 if(typeof c.dataIndex == "undefined"){
15911 if(typeof c.renderer == "string"){
15912 c.renderer = Roo.util.Format[c.renderer];
15914 if(typeof c.id == "undefined"){
15917 // if(c.editor && c.editor.xtype){
15918 // c.editor = Roo.factory(c.editor, Roo.grid);
15920 // if(c.editor && c.editor.isFormField){
15921 // c.editor = new Roo.grid.GridEditor(c.editor);
15924 this.lookup[c.id] = c;
15928 * The width of columns which have no width specified (defaults to 100)
15931 this.defaultWidth = 100;
15934 * Default sortable of columns which have no sortable specified (defaults to false)
15937 this.defaultSortable = false;
15941 * @event widthchange
15942 * Fires when the width of a column changes.
15943 * @param {ColumnModel} this
15944 * @param {Number} columnIndex The column index
15945 * @param {Number} newWidth The new width
15947 "widthchange": true,
15949 * @event headerchange
15950 * Fires when the text of a header changes.
15951 * @param {ColumnModel} this
15952 * @param {Number} columnIndex The column index
15953 * @param {Number} newText The new header text
15955 "headerchange": true,
15957 * @event hiddenchange
15958 * Fires when a column is hidden or "unhidden".
15959 * @param {ColumnModel} this
15960 * @param {Number} columnIndex The column index
15961 * @param {Boolean} hidden true if hidden, false otherwise
15963 "hiddenchange": true,
15965 * @event columnmoved
15966 * Fires when a column is moved.
15967 * @param {ColumnModel} this
15968 * @param {Number} oldIndex
15969 * @param {Number} newIndex
15971 "columnmoved" : true,
15973 * @event columlockchange
15974 * Fires when a column's locked state is changed
15975 * @param {ColumnModel} this
15976 * @param {Number} colIndex
15977 * @param {Boolean} locked true if locked
15979 "columnlockchange" : true
15981 Roo.bootstrap.Table.ColumnModel.superclass.constructor.call(this);
15983 Roo.extend(Roo.bootstrap.Table.ColumnModel, Roo.util.Observable, {
15985 * @cfg {String} header The header text to display in the Grid view.
15988 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
15989 * {@link Roo.data.Record} definition from which to draw the column's value. If not
15990 * specified, the column's index is used as an index into the Record's data Array.
15993 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
15994 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
15997 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
15998 * Defaults to the value of the {@link #defaultSortable} property.
15999 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
16002 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
16005 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
16008 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
16011 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
16014 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
16015 * given the cell's data value. See {@link #setRenderer}. If not specified, the
16016 * default renderer uses the raw data value.
16019 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
16023 * Returns the id of the column at the specified index.
16024 * @param {Number} index The column index
16025 * @return {String} the id
16027 getColumnId : function(index){
16028 return this.config[index].id;
16032 * Returns the column for a specified id.
16033 * @param {String} id The column id
16034 * @return {Object} the column
16036 getColumnById : function(id){
16037 return this.lookup[id];
16042 * Returns the column for a specified dataIndex.
16043 * @param {String} dataIndex The column dataIndex
16044 * @return {Object|Boolean} the column or false if not found
16046 getColumnByDataIndex: function(dataIndex){
16047 var index = this.findColumnIndex(dataIndex);
16048 return index > -1 ? this.config[index] : false;
16052 * Returns the index for a specified column id.
16053 * @param {String} id The column id
16054 * @return {Number} the index, or -1 if not found
16056 getIndexById : function(id){
16057 for(var i = 0, len = this.config.length; i < len; i++){
16058 if(this.config[i].id == id){
16066 * Returns the index for a specified column dataIndex.
16067 * @param {String} dataIndex The column dataIndex
16068 * @return {Number} the index, or -1 if not found
16071 findColumnIndex : function(dataIndex){
16072 for(var i = 0, len = this.config.length; i < len; i++){
16073 if(this.config[i].dataIndex == dataIndex){
16081 moveColumn : function(oldIndex, newIndex){
16082 var c = this.config[oldIndex];
16083 this.config.splice(oldIndex, 1);
16084 this.config.splice(newIndex, 0, c);
16085 this.dataMap = null;
16086 this.fireEvent("columnmoved", this, oldIndex, newIndex);
16089 isLocked : function(colIndex){
16090 return this.config[colIndex].locked === true;
16093 setLocked : function(colIndex, value, suppressEvent){
16094 if(this.isLocked(colIndex) == value){
16097 this.config[colIndex].locked = value;
16098 if(!suppressEvent){
16099 this.fireEvent("columnlockchange", this, colIndex, value);
16103 getTotalLockedWidth : function(){
16104 var totalWidth = 0;
16105 for(var i = 0; i < this.config.length; i++){
16106 if(this.isLocked(i) && !this.isHidden(i)){
16107 this.totalWidth += this.getColumnWidth(i);
16113 getLockedCount : function(){
16114 for(var i = 0, len = this.config.length; i < len; i++){
16115 if(!this.isLocked(i)){
16122 * Returns the number of columns.
16125 getColumnCount : function(visibleOnly){
16126 if(visibleOnly === true){
16128 for(var i = 0, len = this.config.length; i < len; i++){
16129 if(!this.isHidden(i)){
16135 return this.config.length;
16139 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
16140 * @param {Function} fn
16141 * @param {Object} scope (optional)
16142 * @return {Array} result
16144 getColumnsBy : function(fn, scope){
16146 for(var i = 0, len = this.config.length; i < len; i++){
16147 var c = this.config[i];
16148 if(fn.call(scope||this, c, i) === true){
16156 * Returns true if the specified column is sortable.
16157 * @param {Number} col The column index
16158 * @return {Boolean}
16160 isSortable : function(col){
16161 if(typeof this.config[col].sortable == "undefined"){
16162 return this.defaultSortable;
16164 return this.config[col].sortable;
16168 * Returns the rendering (formatting) function defined for the column.
16169 * @param {Number} col The column index.
16170 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
16172 getRenderer : function(col){
16173 if(!this.config[col].renderer){
16174 return Roo.bootstrap.Table.ColumnModel.defaultRenderer;
16176 return this.config[col].renderer;
16180 * Sets the rendering (formatting) function for a column.
16181 * @param {Number} col The column index
16182 * @param {Function} fn The function to use to process the cell's raw data
16183 * to return HTML markup for the grid view. The render function is called with
16184 * the following parameters:<ul>
16185 * <li>Data value.</li>
16186 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
16187 * <li>css A CSS style string to apply to the table cell.</li>
16188 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
16189 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
16190 * <li>Row index</li>
16191 * <li>Column index</li>
16192 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
16194 setRenderer : function(col, fn){
16195 this.config[col].renderer = fn;
16199 * Returns the width for the specified column.
16200 * @param {Number} col The column index
16203 getColumnWidth : function(col){
16204 return this.config[col].width * 1 || this.defaultWidth;
16208 * Sets the width for a column.
16209 * @param {Number} col The column index
16210 * @param {Number} width The new width
16212 setColumnWidth : function(col, width, suppressEvent){
16213 this.config[col].width = width;
16214 this.totalWidth = null;
16215 if(!suppressEvent){
16216 this.fireEvent("widthchange", this, col, width);
16221 * Returns the total width of all columns.
16222 * @param {Boolean} includeHidden True to include hidden column widths
16225 getTotalWidth : function(includeHidden){
16226 if(!this.totalWidth){
16227 this.totalWidth = 0;
16228 for(var i = 0, len = this.config.length; i < len; i++){
16229 if(includeHidden || !this.isHidden(i)){
16230 this.totalWidth += this.getColumnWidth(i);
16234 return this.totalWidth;
16238 * Returns the header for the specified column.
16239 * @param {Number} col The column index
16242 getColumnHeader : function(col){
16243 return this.config[col].header;
16247 * Sets the header for a column.
16248 * @param {Number} col The column index
16249 * @param {String} header The new header
16251 setColumnHeader : function(col, header){
16252 this.config[col].header = header;
16253 this.fireEvent("headerchange", this, col, header);
16257 * Returns the tooltip for the specified column.
16258 * @param {Number} col The column index
16261 getColumnTooltip : function(col){
16262 return this.config[col].tooltip;
16265 * Sets the tooltip for a column.
16266 * @param {Number} col The column index
16267 * @param {String} tooltip The new tooltip
16269 setColumnTooltip : function(col, tooltip){
16270 this.config[col].tooltip = tooltip;
16274 * Returns the dataIndex for the specified column.
16275 * @param {Number} col The column index
16278 getDataIndex : function(col){
16279 return this.config[col].dataIndex;
16283 * Sets the dataIndex for a column.
16284 * @param {Number} col The column index
16285 * @param {Number} dataIndex The new dataIndex
16287 setDataIndex : function(col, dataIndex){
16288 this.config[col].dataIndex = dataIndex;
16294 * Returns true if the cell is editable.
16295 * @param {Number} colIndex The column index
16296 * @param {Number} rowIndex The row index
16297 * @return {Boolean}
16299 isCellEditable : function(colIndex, rowIndex){
16300 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
16304 * Returns the editor defined for the cell/column.
16305 * return false or null to disable editing.
16306 * @param {Number} colIndex The column index
16307 * @param {Number} rowIndex The row index
16310 getCellEditor : function(colIndex, rowIndex){
16311 return this.config[colIndex].editor;
16315 * Sets if a column is editable.
16316 * @param {Number} col The column index
16317 * @param {Boolean} editable True if the column is editable
16319 setEditable : function(col, editable){
16320 this.config[col].editable = editable;
16325 * Returns true if the column is hidden.
16326 * @param {Number} colIndex The column index
16327 * @return {Boolean}
16329 isHidden : function(colIndex){
16330 return this.config[colIndex].hidden;
16335 * Returns true if the column width cannot be changed
16337 isFixed : function(colIndex){
16338 return this.config[colIndex].fixed;
16342 * Returns true if the column can be resized
16343 * @return {Boolean}
16345 isResizable : function(colIndex){
16346 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
16349 * Sets if a column is hidden.
16350 * @param {Number} colIndex The column index
16351 * @param {Boolean} hidden True if the column is hidden
16353 setHidden : function(colIndex, hidden){
16354 this.config[colIndex].hidden = hidden;
16355 this.totalWidth = null;
16356 this.fireEvent("hiddenchange", this, colIndex, hidden);
16360 * Sets the editor for a column.
16361 * @param {Number} col The column index
16362 * @param {Object} editor The editor object
16364 setEditor : function(col, editor){
16365 this.config[col].editor = editor;
16369 Roo.bootstrap.Table.ColumnModel.defaultRenderer = function(value){
16370 if(typeof value == "string" && value.length < 1){
16376 // Alias for backwards compatibility
16377 Roo.bootstrap.Table.DefaultColumnModel = Roo.bootstrap.Table.ColumnModel;
16380 * @extends Roo.bootstrap.Table.AbstractSelectionModel
16381 * @class Roo.bootstrap.Table.RowSelectionModel
16382 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
16383 * It supports multiple selections and keyboard selection/navigation.
16385 * @param {Object} config
16388 Roo.bootstrap.Table.RowSelectionModel = function(config){
16389 Roo.apply(this, config);
16390 this.selections = new Roo.util.MixedCollection(false, function(o){
16395 this.lastActive = false;
16399 * @event selectionchange
16400 * Fires when the selection changes
16401 * @param {SelectionModel} this
16403 "selectionchange" : true,
16405 * @event afterselectionchange
16406 * Fires after the selection changes (eg. by key press or clicking)
16407 * @param {SelectionModel} this
16409 "afterselectionchange" : true,
16411 * @event beforerowselect
16412 * Fires when a row is selected being selected, return false to cancel.
16413 * @param {SelectionModel} this
16414 * @param {Number} rowIndex The selected index
16415 * @param {Boolean} keepExisting False if other selections will be cleared
16417 "beforerowselect" : true,
16420 * Fires when a row is selected.
16421 * @param {SelectionModel} this
16422 * @param {Number} rowIndex The selected index
16423 * @param {Roo.data.Record} r The record
16425 "rowselect" : true,
16427 * @event rowdeselect
16428 * Fires when a row is deselected.
16429 * @param {SelectionModel} this
16430 * @param {Number} rowIndex The selected index
16432 "rowdeselect" : true
16434 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
16435 this.locked = false;
16438 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
16440 * @cfg {Boolean} singleSelect
16441 * True to allow selection of only one row at a time (defaults to false)
16443 singleSelect : false,
16446 initEvents : function(){
16448 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
16449 this.grid.on("mousedown", this.handleMouseDown, this);
16450 }else{ // allow click to work like normal
16451 this.grid.on("rowclick", this.handleDragableRowClick, this);
16454 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
16455 "up" : function(e){
16457 this.selectPrevious(e.shiftKey);
16458 }else if(this.last !== false && this.lastActive !== false){
16459 var last = this.last;
16460 this.selectRange(this.last, this.lastActive-1);
16461 this.grid.getView().focusRow(this.lastActive);
16462 if(last !== false){
16466 this.selectFirstRow();
16468 this.fireEvent("afterselectionchange", this);
16470 "down" : function(e){
16472 this.selectNext(e.shiftKey);
16473 }else if(this.last !== false && this.lastActive !== false){
16474 var last = this.last;
16475 this.selectRange(this.last, this.lastActive+1);
16476 this.grid.getView().focusRow(this.lastActive);
16477 if(last !== false){
16481 this.selectFirstRow();
16483 this.fireEvent("afterselectionchange", this);
16488 var view = this.grid.view;
16489 view.on("refresh", this.onRefresh, this);
16490 view.on("rowupdated", this.onRowUpdated, this);
16491 view.on("rowremoved", this.onRemove, this);
16495 onRefresh : function(){
16496 var ds = this.grid.dataSource, i, v = this.grid.view;
16497 var s = this.selections;
16498 s.each(function(r){
16499 if((i = ds.indexOfId(r.id)) != -1){
16508 onRemove : function(v, index, r){
16509 this.selections.remove(r);
16513 onRowUpdated : function(v, index, r){
16514 if(this.isSelected(r)){
16515 v.onRowSelect(index);
16521 * @param {Array} records The records to select
16522 * @param {Boolean} keepExisting (optional) True to keep existing selections
16524 selectRecords : function(records, keepExisting){
16526 this.clearSelections();
16528 var ds = this.grid.dataSource;
16529 for(var i = 0, len = records.length; i < len; i++){
16530 this.selectRow(ds.indexOf(records[i]), true);
16535 * Gets the number of selected rows.
16538 getCount : function(){
16539 return this.selections.length;
16543 * Selects the first row in the grid.
16545 selectFirstRow : function(){
16550 * Select the last row.
16551 * @param {Boolean} keepExisting (optional) True to keep existing selections
16553 selectLastRow : function(keepExisting){
16554 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
16558 * Selects the row immediately following the last selected row.
16559 * @param {Boolean} keepExisting (optional) True to keep existing selections
16561 selectNext : function(keepExisting){
16562 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
16563 this.selectRow(this.last+1, keepExisting);
16564 this.grid.getView().focusRow(this.last);
16569 * Selects the row that precedes the last selected row.
16570 * @param {Boolean} keepExisting (optional) True to keep existing selections
16572 selectPrevious : function(keepExisting){
16574 this.selectRow(this.last-1, keepExisting);
16575 this.grid.getView().focusRow(this.last);
16580 * Returns the selected records
16581 * @return {Array} Array of selected records
16583 getSelections : function(){
16584 return [].concat(this.selections.items);
16588 * Returns the first selected record.
16591 getSelected : function(){
16592 return this.selections.itemAt(0);
16597 * Clears all selections.
16599 clearSelections : function(fast){
16600 if(this.locked) return;
16602 var ds = this.grid.dataSource;
16603 var s = this.selections;
16604 s.each(function(r){
16605 this.deselectRow(ds.indexOfId(r.id));
16609 this.selections.clear();
16616 * Selects all rows.
16618 selectAll : function(){
16619 if(this.locked) return;
16620 this.selections.clear();
16621 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
16622 this.selectRow(i, true);
16627 * Returns True if there is a selection.
16628 * @return {Boolean}
16630 hasSelection : function(){
16631 return this.selections.length > 0;
16635 * Returns True if the specified row is selected.
16636 * @param {Number/Record} record The record or index of the record to check
16637 * @return {Boolean}
16639 isSelected : function(index){
16640 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
16641 return (r && this.selections.key(r.id) ? true : false);
16645 * Returns True if the specified record id is selected.
16646 * @param {String} id The id of record to check
16647 * @return {Boolean}
16649 isIdSelected : function(id){
16650 return (this.selections.key(id) ? true : false);
16654 handleMouseDown : function(e, t){
16655 var view = this.grid.getView(), rowIndex;
16656 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
16659 if(e.shiftKey && this.last !== false){
16660 var last = this.last;
16661 this.selectRange(last, rowIndex, e.ctrlKey);
16662 this.last = last; // reset the last
16663 view.focusRow(rowIndex);
16665 var isSelected = this.isSelected(rowIndex);
16666 if(e.button !== 0 && isSelected){
16667 view.focusRow(rowIndex);
16668 }else if(e.ctrlKey && isSelected){
16669 this.deselectRow(rowIndex);
16670 }else if(!isSelected){
16671 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
16672 view.focusRow(rowIndex);
16675 this.fireEvent("afterselectionchange", this);
16678 handleDragableRowClick : function(grid, rowIndex, e)
16680 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
16681 this.selectRow(rowIndex, false);
16682 grid.view.focusRow(rowIndex);
16683 this.fireEvent("afterselectionchange", this);
16688 * Selects multiple rows.
16689 * @param {Array} rows Array of the indexes of the row to select
16690 * @param {Boolean} keepExisting (optional) True to keep existing selections
16692 selectRows : function(rows, keepExisting){
16694 this.clearSelections();
16696 for(var i = 0, len = rows.length; i < len; i++){
16697 this.selectRow(rows[i], true);
16702 * Selects a range of rows. All rows in between startRow and endRow are also selected.
16703 * @param {Number} startRow The index of the first row in the range
16704 * @param {Number} endRow The index of the last row in the range
16705 * @param {Boolean} keepExisting (optional) True to retain existing selections
16707 selectRange : function(startRow, endRow, keepExisting){
16708 if(this.locked) return;
16710 this.clearSelections();
16712 if(startRow <= endRow){
16713 for(var i = startRow; i <= endRow; i++){
16714 this.selectRow(i, true);
16717 for(var i = startRow; i >= endRow; i--){
16718 this.selectRow(i, true);
16724 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
16725 * @param {Number} startRow The index of the first row in the range
16726 * @param {Number} endRow The index of the last row in the range
16728 deselectRange : function(startRow, endRow, preventViewNotify){
16729 if(this.locked) return;
16730 for(var i = startRow; i <= endRow; i++){
16731 this.deselectRow(i, preventViewNotify);
16737 * @param {Number} row The index of the row to select
16738 * @param {Boolean} keepExisting (optional) True to keep existing selections
16740 selectRow : function(index, keepExisting, preventViewNotify){
16741 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
16742 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
16743 if(!keepExisting || this.singleSelect){
16744 this.clearSelections();
16746 var r = this.grid.dataSource.getAt(index);
16747 this.selections.add(r);
16748 this.last = this.lastActive = index;
16749 if(!preventViewNotify){
16750 this.grid.getView().onRowSelect(index);
16752 this.fireEvent("rowselect", this, index, r);
16753 this.fireEvent("selectionchange", this);
16759 * @param {Number} row The index of the row to deselect
16761 deselectRow : function(index, preventViewNotify){
16762 if(this.locked) return;
16763 if(this.last == index){
16766 if(this.lastActive == index){
16767 this.lastActive = false;
16769 var r = this.grid.dataSource.getAt(index);
16770 this.selections.remove(r);
16771 if(!preventViewNotify){
16772 this.grid.getView().onRowDeselect(index);
16774 this.fireEvent("rowdeselect", this, index);
16775 this.fireEvent("selectionchange", this);
16779 restoreLast : function(){
16781 this.last = this._last;
16786 acceptsNav : function(row, col, cm){
16787 return !cm.isHidden(col) && cm.isCellEditable(col, row);
16791 onEditorKey : function(field, e){
16792 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
16797 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
16799 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
16801 }else if(k == e.ENTER && !e.ctrlKey){
16805 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
16807 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
16809 }else if(k == e.ESC){
16813 g.startEditing(newCell[0], newCell[1]);
16824 * @class Roo.bootstrap.MessageBar
16825 * @extends Roo.bootstrap.Component
16826 * Bootstrap MessageBar class
16827 * @cfg {String} html contents of the MessageBar
16828 * @cfg {String} weight (info | success | warning | danger) default info
16829 * @cfg {String} beforeClass insert the bar before the given class
16830 * @cfg {Boolean} closable (true | false) default false
16831 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
16834 * Create a new Element
16835 * @param {Object} config The config object
16838 Roo.bootstrap.MessageBar = function(config){
16839 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
16842 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
16848 beforeClass: 'bootstrap-sticky-wrap',
16850 getAutoCreate : function(){
16854 cls: 'alert alert-dismissable alert-' + this.weight,
16859 html: this.html || ''
16865 cfg.cls += ' alert-messages-fixed';
16879 onRender : function(ct, position)
16881 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
16884 var cfg = Roo.apply({}, this.getAutoCreate());
16888 cfg.cls += ' ' + this.cls;
16891 cfg.style = this.style;
16893 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
16895 this.el.setVisibilityMode(Roo.Element.DISPLAY);
16898 this.el.select('>button.close').on('click', this.hide, this);
16904 if (!this.rendered) {
16910 this.fireEvent('show', this);
16916 if (!this.rendered) {
16922 this.fireEvent('hide', this);
16925 update : function()
16927 // var e = this.el.dom.firstChild;
16929 // if(this.closable){
16930 // e = e.nextSibling;
16933 // e.data = this.html || '';
16935 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';